├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ ├── skipped-build.yml
│ ├── security-scanning-csharp.yml
│ └── build.yml
├── .nuke
├── parameters.json
└── build.schema.json
├── .gitattributes
├── .vscode
├── settings.json
└── extensions.json
├── GitVersion.yml
├── nuget.config
├── .gitignore
├── tests
└── XsltTests
│ ├── expected
│ ├── display-name-test.xml
│ ├── passed-test.xml
│ ├── skipped-test.xml
│ ├── inline-data-test.xml
│ └── failed-test.xml
│ ├── input
│ ├── display-name-test.xml
│ ├── passed-test.xml
│ ├── skipped-test.xml
│ ├── inline-data-test.xml
│ └── failed-test.xml
│ ├── ProgramTests.cs
│ ├── XsltTests.csproj
│ └── JUnitTransformerTests.cs
├── xUnitToJUnit.sln.DotSettings
├── src
├── xUnitToJUnit
│ ├── README.md
│ ├── Program.cs
│ ├── xUnitToJUnit.csproj
│ └── JUnitTransformer.cs
└── JUnit.xslt
├── LICENSE
├── Directory.Packages.props
├── README.md
├── xUnitToJUnit.sln
└── .editorconfig
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @gabrielweyer
2 |
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./build.schema.json",
3 | "Solution": "xUnitToJUnit.sln"
4 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Rider
2 | *.DotSettings eol=lf
3 |
4 | *.ps1 linguist-vendored
5 | *.sh linguist-vendored
6 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "yaml.schemas": {
3 | "https://json.schemastore.org/github-workflow.json": "/.github/workflows/*.yml"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-dotnettools.csharp",
4 | "EditorConfig.EditorConfig",
5 | "redhat.vscode-yaml"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | branches:
2 | feature:
3 | mode: ContinuousDeployment
4 | hotfix:
5 | mode: ContinuousDeployment
6 | tag: useBranchName
7 | ignore:
8 | sha: []
9 |
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Rider
2 | .idea/
3 | *.DotSettings.user
4 |
5 | # Visual Studio
6 | .vs/
7 |
8 | # Compilation detritus
9 | obj/
10 | bin/
11 |
12 | # Build
13 | artifacts/
14 |
15 | # NUKE
16 | .nuke/temp/
17 |
18 | # Git
19 | *.orig
20 |
--------------------------------------------------------------------------------
/tests/XsltTests/expected/display-name-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/XsltTests/expected/passed-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/xUnitToJUnit.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "nuget"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | day: "saturday"
8 | ignore:
9 | - dependency-name: "FluentAssertions"
10 | update-types: ["version-update:semver-major"]
11 | groups:
12 | xunit:
13 | patterns:
14 | - xunit
15 | - xunit.analyzers
16 | - xunit.runner.visualstudio
17 |
--------------------------------------------------------------------------------
/tests/XsltTests/expected/skipped-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/tests/XsltTests/expected/inline-data-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.github/workflows/skipped-build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | pull_request:
4 | branches:
5 | - main
6 | paths:
7 | - .github/workflows/security-scanning-csharp.yml
8 | - .github/workflows/skipped-build.yml
9 | - .github/dependabot.yml
10 | - '.vscode/**'
11 | - .editorconfig
12 | - LICENSE
13 | - README.md
14 | jobs:
15 | build:
16 | name: Build
17 | runs-on: ubuntu-latest
18 | steps:
19 | - run: echo "Handling skipped but required check, see https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/troubleshooting-required-status-checks#handling-skipped-but-required-checks"
20 |
--------------------------------------------------------------------------------
/tests/XsltTests/input/display-name-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/tests/XsltTests/expected/failed-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/tests/XsltTests/input/passed-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/tests/XsltTests/input/skipped-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/xUnitToJUnit/README.md:
--------------------------------------------------------------------------------
1 | # xUnit.net v2 XML Format to JUnit Format
2 |
3 | `.NET` [global tool][dotnet-global-tools] transforming a `xUnit.net v2 XML` test results file into a `JUnit` test results file.
4 |
5 | :rotating_light: If you're using this tool to process test results file(s) after having run `dotnet test`, I recommend using the [JUnit Test Logger][junit-logger] instead. The output is better (at least in CircleCI). If you can't install an additional NuGet package in your test project(s), can't modify your build or are processing test results file(s) that have previously been generated, please read on.
6 |
7 | ## Usage
8 |
9 | ```powershell
10 | dotnet xunit-to-junit "path-to-xunit-test-results.xml" "desired-path-to-junit-test-results.xml"
11 | ```
12 |
13 | ## Release notes
14 |
15 | Release notes can be found on [GitHub][release-notes].
16 |
17 | [dotnet-global-tools]: https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools
18 | [junit-logger]: https://github.com/spekt/junit.testlogger
19 | [release-notes]: https://github.com/gabrielweyer/xunit-to-junit/releases
20 |
--------------------------------------------------------------------------------
/src/xUnitToJUnit/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Gabo.DotNet.xUnitToJUnit;
2 |
3 | internal static class Program
4 | {
5 | internal const int SuccessExitCode = 0;
6 | internal const int FailureExitCode = 1;
7 |
8 | internal static int Main(string[] args)
9 | {
10 | if (args.Length != 2)
11 | {
12 | Console.WriteLine("Two arguments should be provided:");
13 | Console.WriteLine(
14 | "dotnet xunit-to-junit \"path-to-xunit-test-results.xml\" \"desired-path-to-junit-test-results.xml\"");
15 | return FailureExitCode;
16 | }
17 |
18 | var xUnitTestResultsFilePath = args[0];
19 | var jUnitTestResultsFilePath = args[1];
20 |
21 | var junitTransformer = new JUnitTransformer();
22 | junitTransformer.Transform(xUnitTestResultsFilePath, jUnitTestResultsFilePath);
23 |
24 | Console.WriteLine(
25 | $"The xUnit test results file \"{xUnitTestResultsFilePath}\" has been converted to the JUnit test results file \"{jUnitTestResultsFilePath}\"");
26 |
27 | return SuccessExitCode;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Gabriel Weyer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/workflows/security-scanning-csharp.yml:
--------------------------------------------------------------------------------
1 | name: "C# Security scanning"
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths-ignore:
8 | - .github/workflows/build.yml
9 | - .github/workflows/skipped-build.yml
10 | - .github/CODEOWNERS
11 | - .github/dependabot.yml
12 | - '.vscode/**'
13 | - .editorconfig
14 | - LICENSE
15 | - README.md
16 | schedule:
17 | - cron: '39 13 * * 5'
18 |
19 | jobs:
20 | analyze:
21 | name: Analyze
22 | runs-on: ubuntu-latest
23 | permissions:
24 | actions: read
25 | contents: read
26 | security-events: write
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'csharp' ]
32 |
33 | steps:
34 | - name: Checkout repository
35 | uses: actions/checkout@v4
36 |
37 | - name: Initialize CodeQL
38 | uses: github/codeql-action/init@v3
39 | with:
40 | languages: ${{ matrix.language }}
41 |
42 | - name: Autobuild
43 | uses: github/codeql-action/autobuild@v3
44 |
45 | - name: Perform CodeQL Analysis
46 | uses: github/codeql-action/analyze@v3
47 |
--------------------------------------------------------------------------------
/Directory.Packages.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | true
5 | AllEnabledByDefault
6 | latest
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/XsltTests/input/inline-data-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/XsltTests/input/failed-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/xUnitToJUnit/xUnitToJUnit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | net8.0
5 | Gabo.DotNet.xUnitToJUnit
6 | dotnet-xunit-to-junit
7 | latest
8 | enable
9 | enable
10 | true
11 | true
12 | true
13 | dotnet-xunit-to-junit
14 | Gabriel Weyer
15 | Transforms a xUnit.net v2 XML test results file into a JUnit test results file.
16 | xUnit JUnit CircleCI
17 | https://github.com/gabrielweyer/xunit-to-junit
18 | README.md
19 | MIT
20 | Copyright © xUnitToJUnit contributors
21 | true
22 | true
23 | snupkg
24 | CS7035;CA1303
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tests/XsltTests/ProgramTests.cs:
--------------------------------------------------------------------------------
1 | namespace Gabo.DotNet.xUnitToJUnit.Tests;
2 |
3 | public sealed class ProgramTests : IDisposable
4 | {
5 | private const string ExistingInputFilePath = "input/passed-test.xml";
6 | private const string OutputDirectory = "output-program";
7 |
8 | [Fact]
9 | public void GivenNoArgumentProvided_ThenFailureExitCode()
10 | {
11 | // Arrange
12 | var input = Array.Empty();
13 |
14 | // Act
15 | var actualExitCode = Program.Main(input);
16 |
17 | // Assert
18 | actualExitCode.Should().Be(Program.FailureExitCode);
19 | }
20 |
21 | [Fact]
22 | public void GivenSingleArgumentProvided_ThenFailureExitCode()
23 | {
24 | // Arrange
25 | var input = new[] { ExistingInputFilePath };
26 |
27 | // Act
28 | var actualExitCode = Program.Main(input);
29 |
30 | // Assert
31 | actualExitCode.Should().Be(Program.FailureExitCode);
32 | }
33 |
34 | [Fact]
35 | public void GivenMoreThanTwoArgumentsProvided_ThenFailureExitCode()
36 | {
37 | // Arrange
38 | var input = new[] { ExistingInputFilePath, ExistingInputFilePath, ExistingInputFilePath };
39 |
40 | // Act
41 | var actualExitCode = Program.Main(input);
42 |
43 | // Assert
44 | actualExitCode.Should().Be(Program.FailureExitCode);
45 | }
46 |
47 | [Fact]
48 | public void GivenTwoValidArgumentsProvided_ThenSuccessExitCode()
49 | {
50 | // Arrange
51 | var input = new[] { ExistingInputFilePath, "valid-arguments.xml" };
52 |
53 | // Act
54 | var actualExitCode = Program.Main(input);
55 |
56 | // Assert
57 | actualExitCode.Should().Be(Program.SuccessExitCode);
58 | }
59 |
60 | public void Dispose()
61 | {
62 | if (Directory.Exists(OutputDirectory))
63 | {
64 | Directory.Delete(OutputDirectory, true);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/XsltTests/XsltTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | Gabo.DotNet.xUnitToJUnit.Tests
5 | Gabo.DotNet.xUnitToJUnit.Tests
6 | latest
7 | enable
8 | enable
9 | false
10 | CS7035;CA1707;CA1515
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | runtime; build; native; contentfiles; analyzers; buildtransitive
19 | all
20 |
21 |
22 |
23 | runtime; build; native; contentfiles; analyzers; buildtransitive
24 | all
25 |
26 |
27 |
28 |
29 | all
30 | runtime; build; native; contentfiles; analyzers; buildtransitive
31 |
32 |
33 |
34 |
35 |
36 |
37 | Always
38 |
39 |
40 | Always
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/JUnit.xslt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | T
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/xUnitToJUnit/JUnitTransformer.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using System.Xml;
3 | using System.Xml.Xsl;
4 |
5 | namespace Gabo.DotNet.xUnitToJUnit;
6 |
7 | ///
8 | /// Transforms a `xUnit.net v2 XML` test results file into a `JUnit` test results file.
9 | ///
10 | internal class JUnitTransformer
11 | {
12 | private readonly XmlWriterSettings _writerSettings;
13 | private readonly XslCompiledTransform _xlsTransform;
14 |
15 | public JUnitTransformer()
16 | {
17 | _xlsTransform = new XslCompiledTransform();
18 | var xsltPath = $"{AppContext.BaseDirectory}/JUnit.xslt";
19 | _xlsTransform.Load(xsltPath);
20 |
21 | if (_xlsTransform.OutputSettings == null)
22 | {
23 | throw new InvalidOperationException($"The XSLT does not contain a xsl:output element ('{xsltPath}').");
24 | }
25 |
26 | _writerSettings = _xlsTransform.OutputSettings.Clone();
27 | _writerSettings.Encoding = new UTF8Encoding(false);
28 | }
29 |
30 | ///
31 | /// Transforms a `xUnit.net v2 XML` test results file into a `JUnit` test results file.
32 | ///
33 | /// The `xUnit.net v2 XML` test results file path.
34 | /// The `JUnit` test results file path, if the containing
35 | /// directory does not exist it will be created.
36 | public void Transform(string xUnitTestResultsFilePath, string jUnitTestResultsFilePath)
37 | {
38 | var jUnitTestResultsDirectory = Path.GetDirectoryName(jUnitTestResultsFilePath);
39 |
40 | if (!string.IsNullOrEmpty(jUnitTestResultsDirectory) && !Directory.Exists(jUnitTestResultsDirectory))
41 | {
42 | Directory.CreateDirectory(jUnitTestResultsDirectory);
43 | }
44 |
45 | using (var stream = new FileStream(jUnitTestResultsFilePath, FileMode.Create, FileAccess.Write))
46 | {
47 | Transform(xUnitTestResultsFilePath, stream);
48 | }
49 | }
50 |
51 | ///
52 | /// Transforms a `xUnit.net v2 XML` test results file into the `JUnit` format and write the result
53 | /// to a Stream.
54 | ///
55 | /// The `xUnit.net v2 XML` test results file path.
56 | /// The output Stream.
57 | public void Transform(string xUnitTestResultsFilePath, Stream stream)
58 | {
59 | using (var results = XmlWriter.Create(stream, _writerSettings))
60 | {
61 | _xlsTransform.Transform(xUnitTestResultsFilePath, results);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xUnit.net v2 XML Format to JUnit Format #
2 |
3 | :rotating_light: If you're using this tool to process test results file(s) after having run `dotnet test`, I recommend using the [JUnit Test Logger][junit-logger] instead. The output is better (at least in CircleCI). If you can't install an additional NuGet package in your test project(s), can't modify your build or are processing test results file(s) that have previously been generated, please read on.
4 |
5 | | Package | Release |
6 | | ----------------------- | ------------------------------------------------ |
7 | | `dotnet-xunit-to-junit` | [![NuGet][nuget-tool-badge]][nuget-tool-command] |
8 |
9 | | CI | Status | Platform(s) | Framework(s) | Test Framework(s) |
10 | | ------------------------ | -------------------------------------------------------- | ----------- | ------------ | ----------------- |
11 | | [GitHub][github-actions] | [![Build Status][github-actions-shield]][github-actions] | `Ubuntu` | `net8.0` | `net8.0` |
12 |
13 | [CircleCI][circle-ci] can only parse test results in the [JUnit format][junit-format]. This `Extensible Stylesheet Language Transformations` can transform a `xUnit.net v2 XML` test results file into a `JUnit` test results file.
14 |
15 | **Note**: this only handles the easiest use case for the moment, as soon as I encounter issues in real life usage I'll add extra testing scenarios.
16 |
17 | ## Consume the transform ##
18 |
19 | ### Consume `JUnit.xslt` through the `dotnet-xunit-to-junit` `NuGet` package ###
20 |
21 | `dotnet-xunit-to-junit` is a `.NET` [global tool][dotnet-global-tools]:
22 |
23 | ```powershell
24 | dotnet tool install -g dotnet-xunit-to-junit
25 | dotnet xunit-to-junit "path-to-xunit-test-results.xml" "desired-path-to-junit-test-results.xml"
26 | ```
27 |
28 | ### Consume `JUnit.xslt` directly from C# ###
29 |
30 | ```csharp
31 | // Required using statement
32 | using System.Xml.Xsl;
33 |
34 | // Change the value of these three variables
35 | const string inputFilePath = "C:/tmp/xunit.xml";
36 | const string outputFilePath = "C:/tmp/junit.xml";
37 | const string xsltFilePath = "C:/tmp/JUnit.xslt";
38 |
39 | var xlsTransform = new XslCompiledTransform();
40 | xlsTransform.Load(xsltFilePath);
41 |
42 | var writerSettings = xlsTransform.OutputSettings.Clone();
43 | // Save without BOM, CircleCI can't read test results files starting with a BOM
44 | writerSettings.Encoding = new UTF8Encoding(false);
45 |
46 | using (var stream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
47 | using (var results = XmlWriter.Create(stream, writerSettings))
48 | {
49 | xlsTransform.Transform(inputFilePath, results);
50 | }
51 | ```
52 |
53 | ## Building locally ##
54 |
55 | Run this command to build on Windows:
56 |
57 | ```powershell
58 | .\build.ps1
59 | ```
60 |
61 | Run this command to build on Linux / macOS:
62 |
63 | ```shell
64 | ./build.sh
65 | ```
66 |
67 | If you want to pack the `.NET Global Tool`, you can run `.\build.ps1 --package`.
68 |
69 | [github-actions]: https://github.com/gabrielweyer/xunit-to-junit/actions/workflows/build.yml
70 | [github-actions-shield]: https://github.com/gabrielweyer/xunit-to-junit/actions/workflows/build.yml/badge.svg
71 | [circle-ci]: https://circleci.com/
72 | [junit-format]: http://llg.cubic.org/docs/junit/
73 | [nuget-tool-badge]: https://img.shields.io/nuget/v/dotnet-xunit-to-junit.svg?label=NuGet
74 | [nuget-tool-command]: https://www.nuget.org/packages/dotnet-xunit-to-junit
75 | [dotnet-global-tools]: https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools
76 | [junit-logger]: https://github.com/spekt/junit.testlogger
77 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | push:
4 | branches:
5 | - main
6 | paths-ignore:
7 | - .github/workflows/security-scanning-csharp.yml
8 | - .github/workflows/skipped-build.yml
9 | - .github/dependabot.yml
10 | - '.vscode/**'
11 | - .editorconfig
12 | - LICENSE
13 | - README.md
14 | pull_request:
15 | branches:
16 | - main
17 | paths-ignore:
18 | - .github/workflows/security-scanning-csharp.yml
19 | - .github/workflows/skipped-build.yml
20 | - .github/dependabot.yml
21 | - '.vscode/**'
22 | - .editorconfig
23 | - LICENSE
24 | - README.md
25 | jobs:
26 | build:
27 | name: Build
28 | runs-on: ubuntu-latest
29 | env:
30 | CREATE_RELEASE: ${{ github.ref_name == 'main' && !contains(github.event.head_commit.message, '[skip-release]') && !contains(github.event.head_commit.message, 'dependabot[bot]') }}
31 | IS_FEATURE_PULL_REQUEST: ${{ github.event_name == 'pull_request' && startsWith(github.head_ref, 'features/') }}
32 | CREATE_PRERELEASE: 'false'
33 | PACKAGE_VERSION:
34 | steps:
35 | - name: Checkout
36 | uses: actions/checkout@v4
37 | with:
38 | fetch-depth: 0
39 | - name: Build
40 | run: ./build.sh --package
41 | - name: Upload NuGet packages
42 | uses: actions/upload-artifact@v4
43 | with:
44 | name: packages
45 | path: ./artifacts/packages
46 | if-no-files-found: error
47 | - name: Upload XSLT transform
48 | uses: actions/upload-artifact@v4
49 | with:
50 | name: transform
51 | path: ./src/JUnit.xslt
52 | if-no-files-found: error
53 | - name: Upload dotnet test results
54 | uses: actions/upload-artifact@v4
55 | with:
56 | name: tests-results
57 | path: ./artifacts/test-results/**/*.html
58 | if-no-files-found: error
59 | if: ${{ always() }}
60 | - name: Upload coverage report
61 | uses: actions/upload-artifact@v4
62 | with:
63 | name: coverage
64 | path: ./artifacts/coverage-report
65 | - name: Determine if we're skipping release on feature Pull Request
66 | if: ${{ env.IS_FEATURE_PULL_REQUEST == 'true' }}
67 | run: |
68 | headCommitMessage=$(git log ${{ github.event.pull_request.head.sha }} -n 1 --format=%B)
69 | echo "HEAD commit message is: $headCommitMessage"
70 | if [[ $headCommitMessage != *"[skip-release]"* ]]; then
71 | echo "CREATE_PRERELEASE=true" >> $GITHUB_ENV
72 | fi
73 | - name: Create GitHub release on main branch
74 | if: ${{ env.CREATE_RELEASE == 'true' }}
75 | env:
76 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77 | run: |
78 | touch empty-release-notes.txt
79 | gh release create v${{ env.PACKAGE_VERSION }} --title v${{ env.PACKAGE_VERSION }} ./artifacts/packages/* --target ${{ github.sha }} --repo ${{ github.repository }} --notes-file empty-release-notes.txt
80 | - name: Create GitHub prerelease on feature Pull Request
81 | if: ${{ env.CREATE_PRERELEASE == 'true' }}
82 | env:
83 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84 | run: |
85 | touch empty-release-notes.txt
86 | gh release create v${{ env.PACKAGE_VERSION }} --title v${{ env.PACKAGE_VERSION }} ./artifacts/packages/* --target ${{ github.sha }} --repo ${{ github.repository }} --notes-file empty-release-notes.txt --prerelease
87 | - name: Push NuGet package on main branch
88 | if: ${{ env.CREATE_RELEASE == 'true' }}
89 | run: dotnet nuget push ./artifacts/packages/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
90 |
--------------------------------------------------------------------------------
/xUnitToJUnit.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio Version 16
3 | VisualStudioVersion = 16.0.28822.285
4 | MinimumVisualStudioVersion = 15.0.26124.0
5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{139529A6-6260-4B32-BA29-D805AF2EBC91}"
6 | EndProject
7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XsltTests", "tests\XsltTests\XsltTests.csproj", "{E59F55FD-E92F-4D0B-8654-CA00237BD758}"
8 | EndProject
9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{14B6EC2B-DF74-4539-B284-466FABE7F70F}"
10 | EndProject
11 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitToJUnit", "src\xUnitToJUnit\xUnitToJUnit.csproj", "{108F0E90-5660-4F79-9F55-1ABA43F787F8}"
12 | EndProject
13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{BD7F1393-1CEF-4033-8FF5-07D5A93072AA}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|x64 = Debug|x64
19 | Debug|x86 = Debug|x86
20 | Release|Any CPU = Release|Any CPU
21 | Release|x64 = Release|x64
22 | Release|x86 = Release|x86
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {BD7F1393-1CEF-4033-8FF5-07D5A93072AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {BD7F1393-1CEF-4033-8FF5-07D5A93072AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|x64.ActiveCfg = Debug|Any CPU
30 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|x64.Build.0 = Debug|Any CPU
31 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|x86.ActiveCfg = Debug|Any CPU
32 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Debug|x86.Build.0 = Debug|Any CPU
33 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|x64.ActiveCfg = Release|Any CPU
36 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|x64.Build.0 = Release|Any CPU
37 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|x86.ActiveCfg = Release|Any CPU
38 | {E59F55FD-E92F-4D0B-8654-CA00237BD758}.Release|x86.Build.0 = Release|Any CPU
39 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|x64.ActiveCfg = Debug|Any CPU
42 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|x64.Build.0 = Debug|Any CPU
43 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|x86.ActiveCfg = Debug|Any CPU
44 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Debug|x86.Build.0 = Debug|Any CPU
45 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|x64.ActiveCfg = Release|Any CPU
48 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|x64.Build.0 = Release|Any CPU
49 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|x86.ActiveCfg = Release|Any CPU
50 | {108F0E90-5660-4F79-9F55-1ABA43F787F8}.Release|x86.Build.0 = Release|Any CPU
51 | EndGlobalSection
52 | GlobalSection(SolutionProperties) = preSolution
53 | HideSolutionNode = FALSE
54 | EndGlobalSection
55 | GlobalSection(NestedProjects) = preSolution
56 | {E59F55FD-E92F-4D0B-8654-CA00237BD758} = {139529A6-6260-4B32-BA29-D805AF2EBC91}
57 | {108F0E90-5660-4F79-9F55-1ABA43F787F8} = {14B6EC2B-DF74-4539-B284-466FABE7F70F}
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {47A69549-61A7-4543-A51B-D96D9EB41663}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/.nuke/build.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "definitions": {
4 | "Host": {
5 | "type": "string",
6 | "enum": [
7 | "AppVeyor",
8 | "AzurePipelines",
9 | "Bamboo",
10 | "Bitbucket",
11 | "Bitrise",
12 | "GitHubActions",
13 | "GitLab",
14 | "Jenkins",
15 | "Rider",
16 | "SpaceAutomation",
17 | "TeamCity",
18 | "Terminal",
19 | "TravisCI",
20 | "VisualStudio",
21 | "VSCode"
22 | ]
23 | },
24 | "ExecutableTarget": {
25 | "type": "string",
26 | "enum": [
27 | "Clean",
28 | "Compile",
29 | "Coverage",
30 | "Pack",
31 | "Restore",
32 | "SetGitHubVersion",
33 | "Test",
34 | "VerifyFormat"
35 | ]
36 | },
37 | "Verbosity": {
38 | "type": "string",
39 | "description": "",
40 | "enum": [
41 | "Verbose",
42 | "Normal",
43 | "Minimal",
44 | "Quiet"
45 | ]
46 | },
47 | "NukeBuild": {
48 | "properties": {
49 | "Continue": {
50 | "type": "boolean",
51 | "description": "Indicates to continue a previously failed build attempt"
52 | },
53 | "Help": {
54 | "type": "boolean",
55 | "description": "Shows the help text for this build assembly"
56 | },
57 | "Host": {
58 | "description": "Host for execution. Default is 'automatic'",
59 | "$ref": "#/definitions/Host"
60 | },
61 | "NoLogo": {
62 | "type": "boolean",
63 | "description": "Disables displaying the NUKE logo"
64 | },
65 | "Partition": {
66 | "type": "string",
67 | "description": "Partition to use on CI"
68 | },
69 | "Plan": {
70 | "type": "boolean",
71 | "description": "Shows the execution plan (HTML)"
72 | },
73 | "Profile": {
74 | "type": "array",
75 | "description": "Defines the profiles to load",
76 | "items": {
77 | "type": "string"
78 | }
79 | },
80 | "Root": {
81 | "type": "string",
82 | "description": "Root directory during build execution"
83 | },
84 | "Skip": {
85 | "type": "array",
86 | "description": "List of targets to be skipped. Empty list skips all dependencies",
87 | "items": {
88 | "$ref": "#/definitions/ExecutableTarget"
89 | }
90 | },
91 | "Target": {
92 | "type": "array",
93 | "description": "List of targets to be invoked. Default is '{default_target}'",
94 | "items": {
95 | "$ref": "#/definitions/ExecutableTarget"
96 | }
97 | },
98 | "Verbosity": {
99 | "description": "Logging verbosity during build execution. Default is 'Normal'",
100 | "$ref": "#/definitions/Verbosity"
101 | }
102 | }
103 | }
104 | },
105 | "allOf": [
106 | {
107 | "properties": {
108 | "Configuration": {
109 | "type": "string",
110 | "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
111 | "enum": [
112 | "Debug",
113 | "Release"
114 | ]
115 | },
116 | "Package": {
117 | "type": "boolean",
118 | "description": "Whether we create the NuGet package - Default is false"
119 | },
120 | "Solution": {
121 | "type": "string",
122 | "description": "Path to a solution file that is automatically loaded"
123 | }
124 | }
125 | },
126 | {
127 | "$ref": "#/definitions/NukeBuild"
128 | }
129 | ]
130 | }
131 |
--------------------------------------------------------------------------------
/tests/XsltTests/JUnitTransformerTests.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace Gabo.DotNet.xUnitToJUnit.Tests;
4 |
5 | public sealed class JUnitTransformerTests : IDisposable
6 | {
7 | private readonly JUnitTransformer _target;
8 | private const string ExistingInputFilePath = "input/passed-test.xml";
9 | private const string OutputDirectory = "output-transformer";
10 |
11 | public JUnitTransformerTests()
12 | {
13 | _target = new JUnitTransformer();
14 | }
15 |
16 | [Fact]
17 | public void GivenOnlyFileNameForOutputPath_WhenTransform_ThenCreateFile()
18 | {
19 | // Act
20 | _target.Transform(ExistingInputFilePath, "junit.xml");
21 |
22 | // Assert
23 | Assert.True(File.Exists("junit.xml"));
24 | }
25 |
26 | [Fact]
27 | public void GivenNonExistingOutputDirectory_WhenTransform_ThenCreateDirectory()
28 | {
29 | // Arrange
30 | const string outputFilePath = $"{OutputDirectory}/circle-ci/junit.xml";
31 | Assert.False(Directory.Exists(OutputDirectory));
32 |
33 | // Act
34 | _target.Transform(ExistingInputFilePath, outputFilePath);
35 |
36 | // Assert
37 | Assert.True(File.Exists(outputFilePath));
38 | }
39 |
40 | [Fact]
41 | public void GivenValidInput_WhenTransform_ThenSaveWithoutBom()
42 | {
43 | // Arrange
44 | const string inputFileName = "passed-test";
45 |
46 | // Act
47 | var actual = Transform(inputFileName);
48 |
49 | // Assert
50 | Assert.Equal('<', actual[0]);
51 | }
52 |
53 | [Fact]
54 | public void GivenPassedTest_WhenTransform_ThenGeneratePassedMarkup()
55 | {
56 | // Arrange
57 | const string inputFileName = "passed-test";
58 |
59 | // Act
60 | var actual = Transform(inputFileName);
61 |
62 | // Assert
63 | var expected = GetExpected(inputFileName);
64 | Assert.Equal(expected, actual);
65 | }
66 |
67 | [Fact]
68 | public void GivenInlineData_WhenTransform_ThenIncludeInlineDataInName()
69 | {
70 | // Arrange
71 | const string inputFileName = "inline-data-test";
72 |
73 | // Act
74 | var actual = Transform(inputFileName);
75 |
76 | // Assert
77 | var expected = GetExpected(inputFileName);
78 | Assert.Equal(expected, actual);
79 | }
80 |
81 | [Fact]
82 | public void GivenDisplayName_WhenTransform_ThenUseDisplayNameInsteadOfEmptyString()
83 | {
84 | // Arrange
85 | const string inputFileName = "display-name-test";
86 |
87 | // Act
88 | var actual = Transform(inputFileName);
89 |
90 | // Assert
91 | var expected = GetExpected(inputFileName);
92 | Assert.Equal(expected, actual);
93 | }
94 |
95 | [Fact]
96 | public void GivenSkippedTest_WhenTransform_ThenGenerateSkippedMarkup()
97 | {
98 | // Arrange
99 | const string inputFileName = "skipped-test";
100 |
101 | // Act
102 | var actual = Transform(inputFileName);
103 |
104 | // Assert
105 | var expected = GetExpected(inputFileName);
106 | Assert.Equal(expected, actual);
107 | }
108 |
109 | [Fact]
110 | public void GivenFailedTest_WhenTransform_ThenGenerateFailedMarkup()
111 | {
112 | // Arrange
113 | const string inputFileName = "failed-test";
114 |
115 | // Act
116 | var actual = Transform(inputFileName);
117 |
118 | // Assert
119 | var expected = GetExpected(inputFileName);
120 | Assert.Equal(expected, actual);
121 | }
122 |
123 | private string Transform(string inputFileName)
124 | {
125 | using var stream = new MemoryStream();
126 | _target.Transform($"./input/{inputFileName}.xml", stream);
127 | return Encoding.UTF8.GetString(stream.ToArray());
128 | }
129 |
130 | private static string GetExpected(string inputFileName)
131 | {
132 | return File.ReadAllText($"./expected/{inputFileName}.xml");
133 | }
134 |
135 | public void Dispose()
136 | {
137 | if (Directory.Exists(OutputDirectory))
138 | {
139 | Directory.Delete(OutputDirectory, true);
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: https://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | [*]
7 | indent_style = space
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.cs]
13 | indent_size = 4
14 |
15 | [*.{xml,csproj,xslt,props}]
16 | indent_size = 2
17 |
18 | [*.xml]
19 | insert_final_newline = false
20 |
21 | [*.json]
22 | indent_size = 2
23 |
24 | [*.ps1]
25 | indent_size = 4
26 |
27 | [*.sh]
28 | end_of_line = lf
29 | indent_size = 2
30 |
31 | # Dotnet code style settings:
32 | [*.cs]
33 |
34 | # Sort using and Import directives with System.* appearing first
35 | dotnet_sort_system_directives_first = true
36 | dotnet_separate_import_directive_groups = false
37 |
38 | # Avoid "this." and "Me." if not necessary
39 | dotnet_style_qualification_for_field = false:error
40 | dotnet_style_qualification_for_property = false:error
41 | dotnet_style_qualification_for_method = false:error
42 | dotnet_style_qualification_for_event = false:error
43 |
44 | # Use language keywords instead of framework type names for type references
45 | dotnet_style_predefined_type_for_locals_parameters_members = true:error
46 | dotnet_style_predefined_type_for_member_access = true:error
47 |
48 | # Suggest more modern language features when available
49 | dotnet_style_object_initializer = true:suggestion
50 | dotnet_style_collection_initializer = true:suggestion
51 | dotnet_style_coalesce_expression = true:suggestion
52 | dotnet_style_null_propagation = true:suggestion
53 | dotnet_style_explicit_tuple_names = true:suggestion
54 |
55 | # Whitespace options
56 | dotnet_style_allow_multiple_blank_lines_experimental = false
57 | dotnet_style_allow_statement_immediately_after_block_experimental = false
58 |
59 | # Non-private static fields are PascalCase
60 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
61 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
62 | dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
63 |
64 | dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
65 | dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
66 | dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
67 |
68 | dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
69 |
70 | # Non-private readonly fields are PascalCase
71 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
72 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
73 | dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
74 |
75 | dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
76 | dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
77 | dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
78 |
79 | dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
80 |
81 | # Constants are PascalCase
82 | dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
83 | dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
84 | dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
85 |
86 | dotnet_naming_symbols.constants.applicable_kinds = field
87 | dotnet_naming_symbols.constants.required_modifiers = const
88 |
89 | dotnet_naming_style.constant_style.capitalization = pascal_case
90 |
91 | # Private instance fields are camelCase and start with _
92 | dotnet_naming_symbols.private_instance_fields.applicable_kinds = field
93 | dotnet_naming_symbols.private_instance_fields.applicable_accessibilities = private
94 |
95 | dotnet_naming_style.private_instance_field_style.capitalization = camel_case
96 | dotnet_naming_style.private_instance_field_style.required_prefix = _
97 |
98 | dotnet_naming_rule.private_instance_fields_should_be_camel_case.severity = warning
99 | dotnet_naming_rule.private_instance_fields_should_be_camel_case.symbols = private_instance_fields
100 | dotnet_naming_rule.private_instance_fields_should_be_camel_case.style = private_instance_field_style
101 |
102 | # Locals and parameters are camelCase
103 | dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
104 | dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
105 | dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
106 |
107 | dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
108 |
109 | dotnet_naming_style.camel_case_style.capitalization = camel_case
110 |
111 | # Local functions are PascalCase
112 | dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
113 | dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
114 | dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
115 |
116 | dotnet_naming_symbols.local_functions.applicable_kinds = local_function
117 |
118 | dotnet_naming_style.local_function_style.capitalization = pascal_case
119 |
120 | # By default, name items with PascalCase
121 | dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
122 | dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
123 | dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
124 |
125 | dotnet_naming_symbols.all_members.applicable_kinds = *
126 |
127 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
128 |
129 | # IDE0035: Remove unreachable code
130 | dotnet_diagnostic.IDE0035.severity = warning
131 |
132 | # IDE0036: Order modifiers
133 | dotnet_diagnostic.IDE0036.severity = warning
134 |
135 | # IDE0043: Format string contains invalid placeholder
136 | dotnet_diagnostic.IDE0043.severity = warning
137 |
138 | # IDE0044: Make field readonly
139 | dotnet_diagnostic.IDE0044.severity = warning
140 |
141 | # IDE0011: Add braces
142 | csharp_prefer_braces = true
143 | # NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201
144 | dotnet_diagnostic.IDE0011.severity = warning
145 |
146 | # IDE0040: Add accessibility modifiers
147 | dotnet_diagnostic.IDE0040.severity = warning
148 |
149 | # CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings?
150 | # IDE0051: Remove unused private member
151 | dotnet_diagnostic.IDE0051.severity = warning
152 |
153 | # IDE0052: Remove unread private member
154 | dotnet_diagnostic.IDE0052.severity = warning
155 |
156 | # IDE0059: Unnecessary assignment to a value
157 | dotnet_diagnostic.IDE0059.severity = warning
158 |
159 | # IDE0060: Remove unused parameter
160 | dotnet_diagnostic.IDE0060.severity = warning
161 |
162 | # CA1012: Abstract types should not have public constructors
163 | dotnet_diagnostic.CA1012.severity = warning
164 |
165 | # CA1822: Make member static
166 | dotnet_diagnostic.CA1822.severity = warning
167 |
168 | # IDE0005: Using directive is unnecessary
169 | dotnet_diagnostic.IDE0005.severity = warning
170 |
171 | # dotnet_style_allow_multiple_blank_lines_experimental
172 | dotnet_diagnostic.IDE2000.severity = warning
173 |
174 | # csharp_style_allow_embedded_statements_on_same_line_experimental
175 | dotnet_diagnostic.IDE2001.severity = warning
176 |
177 | # csharp_style_allow_blank_lines_between_consecutive_braces_experimental
178 | dotnet_diagnostic.IDE2002.severity = warning
179 |
180 | # dotnet_style_allow_statement_immediately_after_block_experimental
181 | dotnet_diagnostic.IDE2003.severity = warning
182 |
183 | # csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental
184 | dotnet_diagnostic.IDE2004.severity = warning
185 |
186 | # CSharp code style settings:
187 | [*.cs]
188 | # Newline settings
189 | csharp_new_line_before_open_brace = all
190 | csharp_new_line_before_else = true
191 | csharp_new_line_before_catch = true
192 | csharp_new_line_before_finally = true
193 | csharp_new_line_before_members_in_object_initializers = true
194 | csharp_new_line_before_members_in_anonymous_types = true
195 | csharp_new_line_between_query_expression_clauses = true
196 |
197 | # Indentation preferences
198 | csharp_indent_block_contents = true
199 | csharp_indent_braces = false
200 | csharp_indent_case_contents = true
201 | csharp_indent_case_contents_when_block = true
202 | csharp_indent_switch_labels = true
203 | csharp_indent_labels = flush_left
204 |
205 | # Whitespace options
206 | csharp_style_allow_embedded_statements_on_same_line_experimental = false
207 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
208 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
209 |
210 | # Prefer "var" everywhere
211 | dotnet_diagnostic.IDE0007.severity = error
212 | csharp_style_var_for_built_in_types = true:error
213 | csharp_style_var_when_type_is_apparent = true:error
214 | csharp_style_var_elsewhere = true:error
215 |
216 | # Prefer method-like constructs to have a block body
217 | csharp_style_expression_bodied_methods = false:none
218 | csharp_style_expression_bodied_constructors = false:none
219 | csharp_style_expression_bodied_operators = false:none
220 |
221 | # Prefer property-like constructs to have an expression-body
222 | csharp_style_expression_bodied_properties = true:error
223 | csharp_style_expression_bodied_indexers = true:error
224 | csharp_style_expression_bodied_accessors = true:error
225 |
226 | # Suggest more modern language features when available
227 | csharp_style_pattern_matching_over_is_with_cast_check = true:error
228 | csharp_style_pattern_matching_over_as_with_null_check = true:error
229 | csharp_style_inlined_variable_declaration = true:suggestion
230 | csharp_style_throw_expression = true:error
231 | csharp_style_conditional_delegate_call = true:suggestion
232 |
233 | # Spacing
234 | csharp_space_after_cast = false
235 | csharp_space_after_colon_in_inheritance_clause = true
236 | csharp_space_after_comma = true
237 | csharp_space_after_dot = false
238 | csharp_space_after_keywords_in_control_flow_statements = true
239 | csharp_space_after_semicolon_in_for_statement = true
240 | csharp_space_around_binary_operators = before_and_after
241 | csharp_space_around_declaration_statements = do_not_ignore
242 | csharp_space_before_colon_in_inheritance_clause = true
243 | csharp_space_before_comma = false
244 | csharp_space_before_dot = false
245 | csharp_space_before_open_square_brackets = false
246 | csharp_space_before_semicolon_in_for_statement = false
247 | csharp_space_between_empty_square_brackets = false
248 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
249 | csharp_space_between_method_call_name_and_opening_parenthesis = false
250 | csharp_space_between_method_call_parameter_list_parentheses = false
251 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
252 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
253 | csharp_space_between_method_declaration_parameter_list_parentheses = false
254 | csharp_space_between_parentheses = false
255 | csharp_space_between_square_brackets = false
256 |
257 | # Blocks are allowed
258 | csharp_prefer_braces = true:silent
259 | csharp_preserve_single_line_blocks = true
260 | csharp_preserve_single_line_statements = true
261 |
262 | # Use file-scope namespace
263 | csharp_style_namespace_declarations = file_scoped:warning
264 |
--------------------------------------------------------------------------------