-
-
Notifications
You must be signed in to change notification settings - Fork 779
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
Add snippet code in html report #1975
Conversation
First all, thank you for picking this up and for formulating your ideas in detail! That's an awesome contribution.
That's fine for version 1. I think you meant syntax coloring, right. There's probably a library that does syntax coloring for Kotlin.
I haven't reviewed it in detail.
The file writing process happens in the abstract base class called
This should be tested thoroughly. There are many cases that could be covered by unit tests.
I'm not sure about that one. I'll ask @arturbosch to provide his expertise.
I don't quite know what you mean by that. Could you please explain that?
Does your report create html files similar to the provided screenshot? |
Ok, let's keep this out of this PR
I didn't explain myself properly. The problem is that the What do you think?
Yes, it's a screenshot of a detekt report with this PR. And that screenshot is a bit old. Now it doesn't underline the spaces. And with #1977 it will not underline the |
CI should pass as soon as #1971 is merged |
No, it won't necessarily, since CodeFactor updates detekt's dependencies on their own. |
Cool PR, thanks! For not opening the file: |
🎉 I don't need to open files anymore! Examples of rules where the snippet is not usefull:
I was thinking about doing something with the lenght of textLocation. If it's larger than X don't show the snippet but we would have some false positives. For example Maybe we should ignore this for now and try to fix the textLocation. The problem of fixig this is that we can break some baselines... Any idea? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
The productive code looks fine to me.
I'd just move the FlowContent
util functions into a separate file, since they do quite a lot.
Please see my comments regarding the tests below.
detekt-cli/src/main/kotlin/io/gitlab/arturbosch/detekt/cli/out/HtmlOutputReport.kt
Outdated
Show resolved
Hide resolved
val code = """ | ||
package cases | ||
// reports 1 - line with just one space | ||
|
||
// reports 1 - a comment with trailing space | ||
// A comment | ||
// reports 1 | ||
class TrailingWhitespacePositive { | ||
// reports 1 - line with just one tab | ||
|
||
// reports 1 | ||
fun myFunction() { | ||
// reports 1 - line with 1 trailing tab | ||
println("A message") | ||
// reports 1 | ||
} | ||
} | ||
""".trimIndent().splitToSequence('\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These test code tests too much. It's hard to maintain.
I think for testing the HTML code snippet, 1 or 2 violations should be sufficient.
assertThat(snippet).isEqualTo(""" | ||
<div> | ||
<pre><code><span class="lineno"> 4 </span>// reports 1 - a comment with trailing space | ||
<span class="lineno"> 5 </span>// A comment | ||
<span class="lineno"> 6 </span>// reports 1 | ||
<span class="lineno"> 7 </span><span class="error">class TrailingWhitespacePositive {</span> | ||
<span class="lineno"> 8 </span> // reports 1 - line with just one tab | ||
<span class="lineno"> 9 </span> | ||
<span class="lineno"> 10 </span> // reports 1 | ||
</code></pre> | ||
</div> | ||
|
||
""".trimIndent() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These asserts test more too much. If we add 1 or 2 violations in the snippet
, this and the following asserts should become easier to read and maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if I understood you. The production code writes one snippet for each finding (fidnig = violation?) so it's impossible to add multiple violations to one single snippet.
Anyway, I agree that the problem of this test is the maintainability. I changed the sample source code onces and I need to change the line numbers in all the assertions. But I don't like the tests that are in this file already. They test nearly nothing. If you, or anyone, has an idea to simplify them but not losing its "power" I would like to improve them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BraisGabin As mentioned, I think 1 integration test that assert the dynamic (generated) parts of the HTML report, could be a good addition to this test group.
So the test checks character by character if the dynamic generated content matches the expected one. The expected string could be put into the resources
folder in the src/test
package.
Does this answer your question?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so. So you say that this tests instead of adding all that """code"""
just create files in the resources
folder and check that the output of the function is the same as the content in those files. Right?
Add add an integration test too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this code is fine here. The val code = "..." should be simplified to contain 2 issues. Then the asserts also becomes much simpler by checking only the HTML content for these 2 issues.
The separate resource is just for the integration test that asserts the full HTML content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val core = "..."
contains 0 errors right now. I have all those tests because they test different cases:
Check that the underline is correct:
- Underline all the line
- Underline part of the line
- Underline multiple lines
Show the correct lines:
- If the error is in the first line I show lines 1 to 4.
- If the error is in the first line I show lines 1 to 5.
- If the error is in the line 7 I show lines 4 to 10 (important to show the change between one digit and 2 digits to be sure that the alignment works, this one is checked)
- If the error is in the penultimate line I show lines 14 to 16.
- If the error is in the last line I show lines 13 to 16.
The case 3 is checked implicitly in the top ones.
Maybe the ones that check the lines that are showed can be simplified to just: contains("1", "2", "3", "4")
. Would that work?
detekt-cli/src/test/kotlin/io/gitlab/arturbosch/detekt/cli/out/HtmlOutputFormatTest.kt
Outdated
Show resolved
Hide resolved
Move the snippet code outside I was thinking about creating a Fake of |
Ok, I changed the integration test. Now I'm mocking the By my side this PR is ready. I have ideas for future improvements but I think that this is OK as first step. Are the tests now ok for you? |
Sorry, for the late reply. For findings concerning a function or class I think we would do the user a favor to print just the function and class headers.
This should be useful? |
I agree. In that case we can move that work to other PRs fixing the |
I will just wait for @schalkms last review :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned, we should consider a mocking library for testing detekt.
Furthermore, I think the unit tests could be more fine-grained.
CC @arturbosch
import org.jetbrains.kotlin.com.intellij.psi.search.SearchScope | ||
import javax.swing.Icon | ||
|
||
class FakePsiFile( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider a mocking library here. This becomes really really hard to maintain.
val code = """ | ||
package cases | ||
// reports 1 - line with just one space | ||
|
||
// reports 1 - a comment with trailing space | ||
// A comment | ||
// reports 1 | ||
class TrailingWhitespacePositive { | ||
// reports 1 - line with just one tab | ||
|
||
// reports 1 | ||
fun myFunction() { | ||
// reports 1 - line with 1 trailing tab | ||
println("A message") | ||
// reports 1 | ||
} | ||
} | ||
""".trimIndent().splitToSequence('\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continued discussion from above:
val core = "..." contains 0 errors right now. I have all those tests because they test different cases:
Check that the underline is correct:
Underline all the line
Underline part of the line
Underline multiple lines
Show the correct lines:
If the error is in the first line I show lines 1 to 4.
If the error is in the first line I show lines 1 to 5.
If the error is in the line 7 I show lines 4 to 10 (important to show the change between one digit and 2 digits to be sure that the alignment works, this one is checked)
If the error is in the penultimate line I show lines 14 to 16.
If the error is in the last line I show lines 13 to 16.
The case 3 is checked implicitly in the top ones.
Maybe the ones that check the lines that are showed can be simplified to just: contains("1", "2", "3", "4"). Would that work?
Yes, please try to split this test up as good as possible. For testing the full HTML reporter we have the integration test.
assertThat(result).contains("<span class=\"description\">A3</span>") | ||
} | ||
|
||
it("integration") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Please provide a more detailed description here.
I simplified the tests that were related with the number of lines. The others I insist that they are needed. They were necessary to develop the feature. |
Codecov Report
@@ Coverage Diff @@
## master #1975 +/- ##
=========================================
Coverage ? 80.84%
Complexity ? 1989
=========================================
Files ? 330
Lines ? 5622
Branches ? 1025
=========================================
Hits ? 4545
Misses ? 537
Partials ? 540
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I already like this feature. 🥇🙂
This removes some boilerplate code from the HtmlOuputFormatTest introduced by #1975.
* Rename it to finding * Add snippet code in html report * Add instegration test * Improve integration test * Simplify tests * Rename test
This removes some boilerplate code from the HtmlOuputFormatTest introduced by detekt#1975.
* Rename it to finding * Add snippet code in html report * Add instegration test * Improve integration test * Simplify tests * Rename test
This removes some boilerplate code from the HtmlOuputFormatTest introduced by detekt#1975.
I'm trying to solve #1779
For get this done I added
kotlinx.html
library, I hope it's ok.This implemetation is really basic. It creates things like this:
Problems that I see and I want some feedback:
I'm not using any prettify library to give a bit of color to the codeout of scopeI don't know what to test exactlyI'm opening the file directly from the path... This have problems, for example for testing because the files doesn't exist. Theif (file.exist())
is a workaround, we should look for a good solutionIf the error is in more than one line I just highlight the first line.On the other hand I copy&pasted some html code from the android linter. I don't know how to point that out in the code.