Skip to content

One adoption, end to end

Everything below is what a real build and a real run printed. Both are captured by commands in this repository rather than typed onto the page, so a message whose wording changed fails a check here instead of misleading you halfway through.

An adopting repository usually has the application’s own project at the root and the project that drives it underneath:

<your repository>/
{adoption.shape.application}
{adoption.shape.driving}

That is the natural place to put it, and it is the arrangement that fails. Every default glob the SDK applies reaches the whole tree below the project file, so the driving project gets compiled into the application.

Built on its own, the driving project is perfectly fine:

dotnet build driving/Driving.csproj --nologoexit 0
  Determining projects to restore...
  Restored <your repository>\driving\Driving.csproj (in 40 ms).
  Driving -> <your repository>\driving\bin\Debug\net10.0-windows\Driving.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.79

Then the application:

dotnet build YourApp.csproj --nologoexit 1
  Determining projects to restore...
  Restored <your repository>\YourApp.csproj (in 38 ms).
<your repository>\obj\Debug\net10.0-windows\.NETCoreApp,Version=v10.0.AssemblyAttributes.cs(4,12): error CS0579: Duplicate 'global::System.Runtime.Versioning.TargetFrameworkAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(13,12): error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(14,12): error CS0579: Duplicate 'System.Reflection.AssemblyConfigurationAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(15,12): error CS0579: Duplicate 'System.Reflection.AssemblyFileVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(16,12): error CS0579: Duplicate 'System.Reflection.AssemblyInformationalVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(17,12): error CS0579: Duplicate 'System.Reflection.AssemblyProductAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(18,12): error CS0579: Duplicate 'System.Reflection.AssemblyTitleAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(19,12): error CS0579: Duplicate 'System.Reflection.AssemblyVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(20,12): error CS0579: Duplicate 'System.Runtime.Versioning.TargetPlatformAttribute' attribute [<your repository>\YourApp.csproj]

Build FAILED.

<your repository>\obj\Debug\net10.0-windows\.NETCoreApp,Version=v10.0.AssemblyAttributes.cs(4,12): error CS0579: Duplicate 'global::System.Runtime.Versioning.TargetFrameworkAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(13,12): error CS0579: Duplicate 'System.Reflection.AssemblyCompanyAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(14,12): error CS0579: Duplicate 'System.Reflection.AssemblyConfigurationAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(15,12): error CS0579: Duplicate 'System.Reflection.AssemblyFileVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(16,12): error CS0579: Duplicate 'System.Reflection.AssemblyInformationalVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(17,12): error CS0579: Duplicate 'System.Reflection.AssemblyProductAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(18,12): error CS0579: Duplicate 'System.Reflection.AssemblyTitleAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(19,12): error CS0579: Duplicate 'System.Reflection.AssemblyVersionAttribute' attribute [<your repository>\YourApp.csproj]
<your repository>\obj\Debug\net10.0-windows\YourApp.AssemblyInfo.cs(20,12): error CS0579: Duplicate 'System.Runtime.Versioning.TargetPlatformAttribute' attribute [<your repository>\YourApp.csproj]
    0 Warning(s)
    9 Error(s)

Time Elapsed 00:00:00.76

Nine errors, every one of them CS0579, every one naming a generated file, and not one of them naming the folder that caused it. With UseWPF on, the project in the brackets can be a _wpftmp project you never wrote — which reads like a WPF problem and sends you looking through XAML.

It is not WPF and it is not the generated files. The driving project’s own build wrote a set of assembly attributes, the application’s globs reached down and compiled them as well as its own, and two copies of one attribute is what CS0579 is.

In the application’s project file, not the driving one:

{adoption.excludes}
dotnet build YourApp.csproj --nologoexit 0
  Determining projects to restore...
  All projects are up-to-date for restore.
  YourApp -> <your repository>\bin\Debug\net10.0-windows\YourApp.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.77

DefaultItemExcludes and not a Compile Remove, because it is every glob and not only that one: Page, Resource and EmbeddedResource reach down there too, and an application with UseWPF on applies all of them.

With the build green there are two files to write and one command to run. This is samples/Walkthrough in this repository — an application with a label and a button, a case written against it, and the four calls an adopting project writes — captured on a desk of its own.

The project declaration, which every relative path resolves against:

{
  "executable": "app/bin/Debug/net10.0-windows/Walkthrough.App.exe",
  "timeouts": { "resolve": 5000, "launch": 15000, "stop": 5000 },
  "attempts": 3
}

The case. It reads the label, presses the button, and reads the label again:

{
  "cases": [
    {
      "name": "pressing the button changes what the label says",
      "catches": "a handler wired to nothing, which leaves the label saying it was never pressed",
      "tags": ["walkthrough"],
      "steps": [
        { "locator": "Text#greeting", "act": "read", "expect": "Nothing pressed yet", "reads": "name" },
        { "locator": "Button#press", "act": "invoke", "named": "press the button" },
        { "locator": "Text#greeting", "act": "read", "expect": "The button was pressed", "reads": "name" }
      ]
    }
  ]
}

Building the two projects:

dotnet build app/Walkthrough.App.csproj --nologoexit 0
  Determining projects to restore...
  Restored <your repository>\app\Walkthrough.App.csproj (in 72 ms).
  Walkthrough.App -> <your repository>\app\bin\Debug\net10.0-windows\Walkthrough.App.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.46
dotnet build driving/Walkthrough.Run.csproj --nologoexit 0
  Determining projects to restore...
  Restored <your repository>\driving\Walkthrough.Run.csproj (in 121 ms).
  Walkthrough.Run -> <your repository>\driving\bin\Debug\net10.0-windows\Walkthrough.Run.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.23

And running every case the sample declares:

dotnet run --project driving/Walkthrough.Run.csproj --no-buildexit 0
Passed: all 1 case, 2 assertions over everything.

  pressing the button changes what the label says
  PASSED (exit 0) - 2 assertions: 2 passed, 0 failed, 0 unchecked

The first line is the claim and the rest is what it rests on. Sentence() states what did not run before it states the outcome, because a pass over two of nine cases is a different claim from a pass — and VerdictSummary.Render is what names an assertion that failed, or one that never ran and the precondition that was absent.

What was captured, and how to take it again

Section titled “What was captured, and how to take it again”

SDK 10.0.401 for the build, 10.0.401 for the run. 6 commands, exit codes 0, 1, 0, 0, 0, 0.

capture-adoption.cmd builds the throwaway tree and rewrites the first half. It needs no desk and no packaged feed, and it answers in seconds.

capture-walkthrough.cmd takes the second half, and it needs both: the case creates a real window and reads it back, and the sample restores the engine from a packed feed the way an adopting repository restores it from nuget.org. Run it the way this repository runs anything that needs a desk — in a guest, through run-tests-vm.cmd.

  • Installing it — the package references, and the MSBuild line an application at a repository root needs.
  • Your first case — the same two files, field by field.
  • Reading the verdict — the other refusal an adoption meets, which is a run that could not get the desk it needed.