Skip to content

Commit

Permalink
Fix issues with primary constructors in records (#1575)
Browse files Browse the repository at this point in the history
* fix issues with primary constuctors in records
  • Loading branch information
daveMueller authored Jan 6, 2024
1 parent cbe4644 commit e9d16b0
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 13 deletions.
2 changes: 2 additions & 0 deletions Documentation/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased

### Fixed
-Uncovered lines in .NET 8 for inheriting records [#1555](https://github.com/coverlet-coverage/coverlet/issues/1555)
-Fix record constructors not covered when SkipAutoProps is true [#1561](https://github.com/coverlet-coverage/coverlet/issues/1561)
-Fix ExcludeFromCodeCoverage does not exclude method in a partial class [#1548](https://github.com/coverlet-coverage/coverlet/issues/1548)
-Fix ExcludeFromCodeCoverage does not exclude F# task [#1547](https://github.com/coverlet-coverage/coverlet/issues/1547)
-Fix issues where ExcludeFromCodeCoverage ignored [#1431](https://github.com/coverlet-coverage/coverlet/issues/1431)
Expand Down
11 changes: 8 additions & 3 deletions src/coverlet.core/Instrumentation/Instrumenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ private void InstrumentType(TypeDefinition type)

if (actualMethod.IsGetter || actualMethod.IsSetter)
{
if (_parameters.SkipAutoProps && actualMethod.CustomAttributes.Any(ca => ca.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName))
if (_parameters.SkipAutoProps && IsCompilerGenerated(actualMethod))
{
continue;
}
Expand Down Expand Up @@ -507,13 +507,18 @@ private void InstrumentType(TypeDefinition type)
IEnumerable<MethodDefinition> ctors = type.GetConstructors();
foreach (MethodDefinition ctor in ctors)
{
if (!ctor.CustomAttributes.Any(IsExcludeAttribute))
if (!ctor.CustomAttributes.Any(IsExcludeAttribute) && !IsCompilerGenerated(ctor))
{
InstrumentMethod(ctor);
}
}
}

private static bool IsCompilerGenerated(IMemberDefinition member)
{
return member.CustomAttributes.Any(ca => ca.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName);
}

private void InstrumentMethod(MethodDefinition method)
{
string sourceFile = method.DebugInformation.SequencePoints.Select(s => _sourceRootTranslator.ResolveFilePath(s.Document.Url)).FirstOrDefault();
Expand Down Expand Up @@ -679,7 +684,7 @@ private Instruction AddInstrumentationCode(MethodDefinition method, ILProcessor
}
);

if (method.DeclaringType.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName))
if (IsCompilerGenerated(method.DeclaringType))
{
if (_branchesInCompiledGeneratedClass == null)
{
Expand Down
54 changes: 48 additions & 6 deletions test/coverlet.core.tests/Coverage/CoverageTests.AutoProps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void SkipAutoPropsInRecords(bool skipAutoProps)

if (skipAutoProps)
{
TestInstrumentationHelper.GetCoverageResult(path).GenerateReport(show: true)
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 23, 24)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 23, 24)
Expand All @@ -106,7 +106,7 @@ public void SkipAutoPropsInRecords(bool skipAutoProps)
}
}

[Theory(Skip = "fails reason unknown (no session debug possible)")]
[Theory]
[InlineData(true)]
[InlineData(false)]
public void SkipRecordWithProperties(bool skipAutoProps)
Expand All @@ -116,7 +116,7 @@ public void SkipRecordWithProperties(bool skipAutoProps)
{
FunctionExecutor.Run(async (string[] parameters) =>
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithAutoRecordProperties>(instance =>
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithRecordsAutoProperties>(instance =>
{
return Task.CompletedTask;
},
Expand All @@ -133,14 +133,56 @@ public void SkipRecordWithProperties(bool skipAutoProps)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 29, 29)
.AssertLinesCovered(BuildConfiguration.Debug, (32, 1), (33, 1), (34, 1))
.AssertLinesCovered(BuildConfiguration.Release, (33, 1));

}
else
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertLinesCovered(BuildConfiguration.Debug, (29, 3), (31, 1), (32, 1), (33, 1), (34, 1))
.AssertLinesCovered(BuildConfiguration.Release, (29, 3), (31, 1), (33, 1));
.AssertLinesCovered(BuildConfiguration.Debug, (29, 1), (31, 1), (32, 1), (33, 1), (34, 1))
.AssertLinesCovered(BuildConfiguration.Release, (29, 1), (31, 1), (33, 1));
}
}
finally
{
File.Delete(path);
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void SkipInheritingRecordsWithProperties(bool skipAutoProps)
{
string path = Path.GetTempFileName();
try
{
FunctionExecutor.Run(async (string[] parameters) =>
{
CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run<ClassWithInheritingRecordsAndAutoProperties>(instance =>
{
return Task.CompletedTask;
},
persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1]));

return 0;
}, new string[] { path, skipAutoProps.ToString() });

if (skipAutoProps)
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertNonInstrumentedLines(BuildConfiguration.Debug, 39, 39)
.AssertNonInstrumentedLines(BuildConfiguration.Release, 39, 39)
.AssertLinesCovered(BuildConfiguration.Debug, (41, 1), (44, 1), (45, 1), (46, 1))
.AssertLinesCovered(BuildConfiguration.Release, (45, 1));

}
else
{
TestInstrumentationHelper.GetCoverageResult(path)
.Document("Instrumentation.AutoProps.cs")
.AssertLinesCovered(BuildConfiguration.Debug, (39, 1), (41, 1), (44, 1), (45, 1), (46, 1))
.AssertLinesCovered(BuildConfiguration.Release, (39, 1), (41, 1), (45, 1));
}
}
finally
Expand Down
22 changes: 18 additions & 4 deletions test/coverlet.core.tests/Samples/Instrumentation.AutoProps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,27 @@ public RecordWithPropertyInit()
public string RecordAutoPropsInit { get; set; } = string.Empty;
}

public class ClassWithAutoRecordProperties
public class ClassWithRecordsAutoProperties
{
record AutoRecordWithProperties(string Prop1, string Prop2);
record RecordWithPrimaryConstructor(string Prop1, string Prop2);

public ClassWithAutoRecordProperties()
public ClassWithRecordsAutoProperties()
{
var record = new AutoRecordWithProperties(string.Empty, string.Empty);
var record = new RecordWithPrimaryConstructor(string.Empty, string.Empty);
}
}

public class ClassWithInheritingRecordsAndAutoProperties
{
record BaseRecord(int A);

record InheritedRecord(int A) : BaseRecord(A);

public ClassWithInheritingRecordsAndAutoProperties()
{
var record = new InheritedRecord(1);
}
}


}

0 comments on commit e9d16b0

Please sign in to comment.