Conversation
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new “typed view” abstraction for authoring cDAC tests by modeling mock target-memory structures as strongly-typed wrappers over Memory<byte>, aiming to make tests easier to read and to decouple mock-structure construction from cDAC implementation specifics.
Changes:
- Added
Layout/TypedViewinfrastructure for defining field layouts and reading/writing fields without manual span slicing. - Added
MockBuiltInComBuilderand typed wrappers for COM-related runtime structures used byBuiltInCOMTests. - Refactored
BuiltInCOMTeststo allocate/populate mock COM structures via typed wrappers and to create contract type info/globals from layouts.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/managed/cdac/tests/TypedView.cs | New base class for typed wrappers over mock memory with endian/pointer-size aware field access. |
| src/native/managed/cdac/tests/Layout.cs | New layout and layout-builder abstractions for describing mock structure shapes. |
| src/native/managed/cdac/tests/MockBuiltInComBuilder.cs | New COM-specific typed wrappers and allocation helpers used by COM contract tests. |
| src/native/managed/cdac/tests/TargetTestHelpers.cs | Adds CreateTypeInfo(Layout) adapter to convert layouts into Target.TypeInfo. |
| src/native/managed/cdac/tests/BuiltInCOMTests.cs | Refactors tests to use typed wrappers + builder and generates globals/types from layouts. |
| src/native/managed/cdac/tests/README.md | Documents the new TypedView/Layout pattern and when to prefer it in tests. |
| fields[field.Name] = new Target.FieldInfo | ||
| { | ||
| Offset = field.Offset, | ||
| Type = DataType.Unknown, | ||
| }; | ||
| } |
There was a problem hiding this comment.
CreateTypeInfo sets every Target.FieldInfo.Type to DataType.Unknown. That makes the resulting TypeInfo unusable with helpers like SizeOfTypeInfo (which throws for non-primitive types) and may limit reuse of these TypeInfos elsewhere in tests. Consider inferring a primitive type from LayoutField.Size (or extending LayoutField to carry a lightweight kind) so emitted FieldInfo.Type is at least a usable primitive.
There was a problem hiding this comment.
I agree, it would be good to pass through the proper type info here.
There was a problem hiding this comment.
We certainly could provide it but I want to poke at this a bit. My understanding is that the official data descriptor provided by the runtime doesn't provide this type information and thus far every test I've looked at passed without providing it. I was a little worried that if we provide the data we might be giving cDAC a crutch where it will assume the type information is available and then fail against a real target which doesn't provide equally rich type information.
SizeOfTypeInfo looked similarly suspicious where the test is making a size computation by summing the field sizes but the production code probably can't rely on being able to do the same thing.
max-charlamb
left a comment
There was a problem hiding this comment.
I'm happy with this change. It will make unit tests easier to write and understand.
It may be nice to put the test infrastructure in a sub-folder.
| fields[field.Name] = new Target.FieldInfo | ||
| { | ||
| Offset = field.Offset, | ||
| Type = DataType.Unknown, | ||
| }; | ||
| } |
There was a problem hiding this comment.
I agree, it would be good to pass through the proper type info here.
Refactor BuiltInCOMTests to use typed Layout/TypedView wrappers and a focused MockBuiltInComBuilder instead of hand-written mock memory setup. The tests now model runtime shapes more directly, including ComMethodTable trailing vtables, StdInterfaceDesc standard-interface vtables, and RCW inline interface-entry storage. Also document the TypedView pattern in the cDAC test README and align the RCW mock layout and helpers with the runtime's descriptor definitions so the sample better demonstrates the intended refactoring direction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
d3e7a97 to
35141e0
Compare
|
I rebased to fix merge issues, updated the PR based on changes in the underlying COM tests recently, and addressed most of the feedback. One issue that is still outstanding is the field type data which I can happily do but I wanted to the conversation to close first. |
This is an incomplete refactor but I wanted to show a slice of it for feedback before going to deep. I have two goals I am trying to get closer to:
In terms of those two goals:
Understandability
Today some of our tests do all their allocations and data writing in terms of low level byte buffer manipulation. Copilot however has no trouble producing strongly typed views over those buffers if you ask it to and I think it makes tests far easier to understand. As a simple comparison:
BEFORE:
AFTER:
That MockComCallWrapper is just a typed wrapper over a
Memory<byte>using aLayoutto understand where the fields are. When you set the properties SimpleWrapper/Next the property setters are doing the same work asWritePointerin the first example, just without all the obvious buffer manipulation.builtInCom.AddComCallWrapper()is also just giving a convenient API to allocate the HeapFragment, wrap it in the typed view object, and add the fragment to the builder. Tests still have full access to write raw HeapFragments if they want to, or the Memory is available from the typed view. I'm not trying to stop tests from dropping into the weeds when its useful. TypedViews also aren't compelled to have any specific set of accessors on them - tests can make them as rich or lean as they want. So far I've just been having copilot add accessors for the fields that tests interacted with.Extracting out runtime data mocking logic
Continuing to use BuiltInComTests as an example, the previous file was a mixture of layout definitions, global definitions, target creation, data structure allocation, and the unit tests themselves. A little more subtle, the test's definition of MockDescriptors.TypeFields has a cDAC DataType field inside of it which forces a cDAC library dependency in order to generate the data. Similarly creating the actual layout offsets produces TypeInfo objects which are cDAC abtractions as well. In the factored version MockBuiltInComBuilder.cs has all the type information, typed wrappers, and allocation helpers that could be reused for mocking any runtime COM data structures without any cDAC assembly dependencies. I created a simple Layout/LayoutField abstraction that doesn't have that coupling. Calling
CreateTypeInfoconverts a Layout into a Target.TypeInfo. Not included in this PR but I confirmed its also possible to serialize the Layouts into a contract descriptor JSON blob inside a HeapFragment and then point cDAC at that memory if we want to.My proposal is to continue doing this refactor through the remainder of the cDAC unit tests (I can deal with it) and then we'll be in a better shape for the split that Juan's PR was trying to do. The refactor shouldn't need to touch any of the product code and its easy to verify all the tests pass at any point along the way. Depending on how folks would like to review it I could either prepare one big PR that does it in one shot or I could incrementally convert a portion of the tests at a time, similar to this PR.
But before I do anything more - thoughts on the direction?