Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Source Generator #457

Closed
latop2604 opened this issue Oct 20, 2021 · 17 comments
Closed

Support for Source Generator #457

latop2604 opened this issue Oct 20, 2021 · 17 comments

Comments

@latop2604
Copy link

Describe the bug
Hello,

I use altcover (global tool) to generate code coverage for an .Net5.0 app. And use the result as open cover format to generate report with Report-Generator.

The line coverage is ok. But report generator is unable to find related file. (Understandable as source generated file are in memory only by default.

I don't know if it's in altcover scope or in report generator. Or both.

And btw, thx for your great work on this tool.

To Reproduce

  • Add a source generator to your app
  • Add some test on the generated code
  • Run coverage tool (here is altcover) in opencover format
  • Generate html report from the coverage file

image

@danielpalme
Copy link
Owner

ReportGenerator parses file coverage file generated by altcover, but is unable to find the file.
As you said, the file does not exist on your disk.
I guess there is nothing I can do about it.

One option might be to ignore the file with -filefilters:-*Generated.cs

@latop2604
Copy link
Author

When adding the property <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> in the csproj file. The generated file is available but in Obj directory. Maybe some path lookup fallback can be an option ?

image

@danielpalme
Copy link
Owner

danielpalme commented Oct 20, 2021

And what path does the altcover file contain, when you add the EmitCompilerGeneratedFiles=true option?
Does it point to the obj directory?

@latop2604
Copy link
Author

Unfortunately, the path in the report file is still the same

@danielpalme
Copy link
Owner

danielpalme commented Oct 21, 2021

Then you could replace the path in the file with the correct one in the obj directory.
You can do that with a little powershell script before executing ReportGenerator.

Example (you have to adjust paths and filenames):

(gc "opencover.xml") | % { $_ -replace "/TODO1/HangFireJobs.Generated.cs", "/TODO2/HangFireJobs.Generated.cs" } | Out-File "opencover.xml" -Encoding UTF8

@latop2604
Copy link
Author

Ah, cool. I will try this. Thank

@latop2604
Copy link
Author

latop2604 commented Oct 21, 2021

It worked 🎉

Only a chunk of the path was missing and does not depend on the project the generator is installed. So this bash command for all project at once. It's still a hack but not so much. We can live with it.

- sed -i "s/Marketplace.Common.Generators\//obj\/Debug\/net5.0\/generated\/Marketplace.Common.Generators\//g" *.opencover.xml

Thank you the the help.

I let you close this issue if you think it should.

@danielpalme
Copy link
Owner

Great that it is working for you!

@SteveGilham
Copy link

In the next release, AltCover will include embedded source in the reports it emits, which can be used to mitigate this issue. The source is represented as UTF8 string -> bytes -> deflate compression -> Base64 encoded string.

For OpenCover format, there is an altcover.embed attribute added to the File element; for NCover classic, altcover.file elements are added after the method records in a module, with attributes document and embed; and for the extended coverlet JSON format, as a type «AltCover.embed» with an empty method with name being the embedded text.

Samples follow --
AltCoverEmbeddingSamples.zip

@SteveGilham
Copy link

And what path does the altcover file contain, when you add the EmitCompilerGeneratedFiles=true option? Does it point to the obj directory?

For the record, AltCover, like other coverage tools, relies on the information provided in the debug symbols for source paths. If this is an embellishment of the reality, the issue lies with the compiler that puts that information into the debug database. Fortunately the compiler does embed the source by default, which would be used for e.g. debug step-into, hence the change alluded to above.

@danielpalme
Copy link
Owner

And the next version of ReportGenerator will support embedded source files for OpenCover.
I will probably release end of next week (after .NET 6 is published).

@SteveGilham
Copy link

We're both waiting on .net 6, then. I suspect there will be a lot of similar upgrade versions dropping all week.

@SteveGilham
Copy link

After some delays e.g. Windows Defender being over-enthusiastic, feature released as part of AltCover v8.2.828

@danielpalme
Copy link
Owner

ReportGenerator has been updated too:
https://www.nuget.org/packages/ReportGenerator/5.0.0

@terryaney
Copy link

Doesn't seem to be working for me in .NET 7 for LoggerMessageGenerator\LoggerMessage.g.cs files?

image

image

@danielpalme
Copy link
Owner

@terryaney
ReportGenerator only supports embedded source files for OpenCover coverage files.

Your Coberatura files probably contains the file paths that (no longer) exist on disk. E.g. C:\BTR\Camelot\Api\Api\src\Microsoft.Extensions.Logging.Generators\Microsoft. xtensions.Logging.Generators.LoggerMessageGenerator\LoggerMessage.g.cs

@terryaney
Copy link

Thanks. Note, in my dotnet test, I used "/p:ExcludeByFile=**/LoggerMessage.g.cs", in tasks.json and it worked. However, "/p:ExcludeByAttribute=GeneratedCodeAttribute", did not work. I thought it would given this:

namespace KAT.Camelot.Api.DataLocker.Features
{
    partial class BaseFileEndpoint<TRequest, TResponse>
    {
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.9.7226")]
        private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.String, global::System.String, global::System.Exception?> __LogWarningUnauthorizedAccessCallback =
            global::Microsoft.Extensions.Logging.LoggerMessage.Define<global::System.String, global::System.String>(global::Microsoft.Extensions.Logging.LogLevel.Warning, new global::Microsoft.Extensions.Logging.EventId(1, nameof(LogWarningUnauthorizedAccess)), "Camelot DataLocker Unauthorized access by {user}: {message}", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); 

        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.9.7226")]
        static partial void LogWarningUnauthorizedAccess(global::Microsoft.Extensions.Logging.ILogger logger, global::System.String user, global::System.String message)
        {
            if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Warning))
            {
                __LogWarningUnauthorizedAccessCallback(logger, user, message, null);
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants