coverlet icon indicating copy to clipboard operation
coverlet copied to clipboard

[BUG] Records show no coverage

Open tisonv opened this issue 1 year ago • 16 comments

Describe the bug With .Net 8, records show no coverage Tested with the nightly build too I read #1561 #1607 #1576

To Reproduce

public sealed record FolderInfoDto
{
    public bool IsHidden { get; init; }
    public long Creation { get; init; }
}
return new FolderInfoDto
{
    Creation = f.Creation,
    IsHidden = !string.IsNullOrEmpty(f.Mode) && 'h' == f.Mode[3]
};
internal abstract record BasicFolderDto
{
    public string? DfsMappedPath { get; init; }
    public string Path { get; init; } = null!;
}

internal sealed record CreateFolderDto : BasicFolderDto;

CreateFolderDto dto = new()
{
    Path = args != null && args.TryGetValue("path", out var path) ? (string)path : @"F:\rep1\rep2",
};
internal sealed record DeleteFolderDto : BasicFolderDto
{
    public bool Recurse { get; init; }
    public bool Force { get; init; }
}

DeleteFolderDto dto = new()
{
    Path = @"L:\path\",
};

Expected behavior FolderInfoDto, CreateFolderDto, DeleteFolderDto, BasicFolderDto are marked as covered.

Actual behavior They are marked as not covered.

Configuration (please complete the following information): Please provide more information on your .NET configuration: * Which coverlet package and version was used? 6.0.1 and nightly * Which version of .NET is the code running on? 8.0.2 * What OS and version, and what distro if applicable? Windows 11 * What is the architecture (x64, x86, ARM, ARM64)? x64 * Do you know whether it is specific to that configuration? No

Additional context

  • Same result from Visual Studio and CLI
  • No difference with either <TargetFramework>net8.0</TargetFramework> or <TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
  • removing abstract or sealed makes no difference
  • SkipAutoProps makes no difference

test.runsettings:

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
	<RunConfiguration>
		<ResultsDirectory>.\TestResults</ResultsDirectory>
		<TargetPlatform>x64</TargetPlatform>
		<TargetFramework>net8.0</TargetFramework>
	</RunConfiguration>

	<DataCollectionRunSettings>
		<DataCollectors>
			<DataCollector friendlyName="XPlat code coverage">
				<Configuration>
					<Format>cobertura</Format>
					<Exclude>[coverlet.*.tests?]*,[*]Coverlet.Core*,[*]xunit*</Exclude>
				</Configuration>
			</DataCollector>
		</DataCollectors>
	</DataCollectionRunSettings>
</RunSettings>

:exclamation: Please also read Known Issues

tisonv avatar Feb 27 '24 14:02 tisonv

Thanks for reporting and providing a repro. I see if I can get the discussion in #1576 started. I think we then would have less issues with records.

daveMueller avatar Feb 28 '24 12:02 daveMueller

Our SonarQube would not allow my PR since coverage was subpar. I was just refactoring dtos . I had to [ExcludeFromCodeCoverage] for the time being

tisonv avatar Feb 28 '24 12:02 tisonv

Could you elaborate a bit on how to reproduce this? With my setup I can get coverage for those records.

grafik

daveMueller avatar Mar 26 '24 22:03 daveMueller

Hello !

Latest SonarQube expects all the lines to be covered https://community.sonarsource.com/t/sonarqube-not-showing-coverage-for-inherited-record/107476 I'm not sure whether they should be marked as covered or not

image

tisonv avatar Apr 02 '24 09:04 tisonv

A hopefully useful additional data point

  • Visual Studio 2022 17.10.0
  • FineCodeCoverage 1.1.215
  • NUnit 4.1.0
  • coverlet.collector 6.0.2
  • C# 12
  • .NET 8

I have an internal record:

internal record Foo
{
    public string Bar() => "baz";
}

And an associated test project with a test:

[TestFixture]
internal class FooTests
{
    [Test]
    public void FooBarShouldReturnBaz()
    {
        var foo = new Foo();
        Assert.That(foo.Bar(), Is.EqualTo("baz"));
    }
}

After running the test, the method call shows that it was covered, but the record itself does not:

image

If I modify the record declaration to include the redundant primary constructor parentheses:

internal record Foo()
{
    public string Bar() => "baz";
}

and repeat the test, this time I get green all around:

image

Steve-OH avatar Jun 27 '24 02:06 Steve-OH

I confirm Thanks @Steve-OH !

tisonv avatar Jul 02 '24 07:07 tisonv

I have similar issue, it gets fixed if i remove my constructor and use the parenthesis in record declaration. Here's an example:

image

Note that constructor without coverage seems to accept an argument of the same type.

And here it's gone:

image

Rast1234 avatar Jul 23 '24 16:07 Rast1234

Hello !

Latest SonarQube expects all the lines to be covered https://community.sonarsource.com/t/sonarqube-not-showing-coverage-for-inherited-record/107476 I'm not sure whether they should be marked as covered or not

image

OK I see. It looks like SonarQube is expecting the record declaration as something that should be covered. This is something we are not doing. If you ignore all the generated IL of a record it is just the same as a simple class declaration. Is SonarQube expecting coverage for a class declaration? I don't think so because it doesn't really have any executable code.

image

daveMueller avatar Aug 13 '24 23:08 daveMueller

@Steve-OH, @Rast1234 I think I now found one of the issues here. Starting from the sample code @Steve-OH provided. If I add the primary constructor parentheses, the generated report contains the constructor. This is an issue we need to tackle.

image

If it doesn't contain the parentheses the constructor is not part of the coverage report. Which should be the expected report in both cases because we want generated constructors to be completely excluded.

image

But in your sample, the record declaration seems to be expected to be covered also without the parentheses. This is different to what I'm currently observing. I wonder if this is part of the report? Are you able to provide me your coverage reports for both cases?

343599532-16bb60d4-c039-4dc7-914e-b82a0ada373c

daveMueller avatar Aug 14 '24 00:08 daveMueller

Here are the reports, with and without parentheses.

coverlet-test.zip

Steve-OH avatar Aug 15 '24 00:08 Steve-OH