Skip to content

SONARCH-708, SONARJAVA-5497: Extend SonarJava CheckRegistrar API for registering custom file scanner hooks #5083

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

kaufco
Copy link
Contributor

@kaufco kaufco commented Apr 11, 2025

@kaufco kaufco force-pushed the marco/SONARCH-708 branch from 1a75e68 to b6c30f1 Compare April 11, 2025 16:15
@kaufco kaufco marked this pull request as ready for review April 11, 2025 16:43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the change looks simple enough to integrated as-is, but there are a couple of questions I have left for you to look at.

In addition, I thin that he ticket attached to this PR should be a SONARJAVA ticket because this change implies a modification of the public API and should be properly documented as part of the release

@Test
void empty_default_method_coverage() {
var context = new CheckRegistrar.RegistrarContext();
assertDoesNotThrow(() -> context.registerCustomFileScanner(null, null));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are we testing here? Isn't the default implementation of registerCustomFileScanner empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but QG failed due to low coverage. Even if the method is empty, it must still be tested. So just making sure the method is there and can be called without issues is the best thing we can do here I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary from our discussion:

  • If we introduced a return value just for testing, then what we really would be testing is only that the method does not terminate abnormally. We wouldn't be testing any behavior. I.e., if the method returns true, this does not proof anything what the method does or does not do apart from returning true.
  • Therefore, a return value only for the matter of testing an empty method is redundant. Normal termination is equivalent to the method not throwing an exception, so we can test that instead. assertTrue(context.registerCustomFileScanner(null, null)) would look nicer in the test, but it does not justify modifying the API
  • If we add a return value, it must have a true semantical meaning, not be introduced only for the testing. What we could do: a return value false indicates that the registration failed. The registrar could then print a log message or something.

@@ -96,6 +97,12 @@ class Scanner implements JavaCheck {
"register 3 instantiated test checks.");
}

@Test
void empty_default_method_coverage() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To help understanding the intent of the test, it would help if the test a name in the form of an assertion (that should not be broken)

Copy link
Contributor Author

@kaufco kaufco Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of the method is just to get coverage for an empty default method (see the other comment). Naming the method registerCustomFileScanner_does_not_throw_exception would satisfy your request, but still I think it doesn't capture well the purpose of the test. I renamed it to cover_empty_default_implementations. Wdyt?

/**
* Registers a custom file scanner not related to any rule or repository.
*/
public void registerCustomFileScanner(RuleScope ruleScope, JavaFileScanner scanner) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpicking: Have we considered returning some value here? To test that something was added, we need to look into the internals of the Checkregistrar implementation. It works here but does not promote good testing practices in the custom plugins downstream.

Copy link
Contributor Author

@kaufco kaufco Apr 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should stick to the pattern used in CheckRegistrar and not be doing it different for a single method: all the register* methods have a void return type.

If we want to change that, I think it should be done in a separate ticket, because changing it for all methods would clearly go beyond the scope of this PR (and also break backwards compatibility on the bytecode level, because even though source code level compatibility does remain, the method signatures would change in the class files).

Comment on lines 312 to 317
if (ruleScope != RuleScope.TEST) {
mainChecks.add(scanner);
}
if (ruleScope != RuleScope.MAIN) {
testChecks.add(scanner);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we arrange these tests in a less clever but more explicit way?

Suggested change
if (ruleScope != RuleScope.TEST) {
mainChecks.add(scanner);
}
if (ruleScope != RuleScope.MAIN) {
testChecks.add(scanner);
}
if (ruleScope == RuleScope.MAIN || ruleScope == RuleScope.ALL) {
mainChecks.add(scanner);
}
if (ruleScope == RuleScope.TEST || ruleScope == RuleScope.ALL) {
testChecks.add(scanner);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines 79 to 84
if (ruleScope != RuleScope.TEST) {
registerMainHook(scanner);
}
if (ruleScope != RuleScope.MAIN) {
registerTestHook(scanner);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we change the implemetation in SonarComponents, we might as well change it here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@kaufco kaufco changed the title SONARCH-708 SonarJava: extend CheckRegistrar API for registering custom file scanner hooks SONARCH-708, SONARJAVA-5497: Extend SonarJava CheckRegistrar API for registering custom file scanner hooks Apr 17, 2025
@kaufco kaufco force-pushed the marco/SONARCH-708 branch 2 times, most recently from b223127 to c20a76d Compare April 17, 2025 15:27
@dorian-burihabwa-sonarsource
Copy link
Contributor

I think what bothers me most is the need to test an empty method and the lack of guidance for what a good implementation of registerCustomFileScanner should look like.

After discussing with @kaufco, it looks like we have 2 options to improve the current proposal.

  1. Improve the documentation of the new method to describe what a good implementation of registerCustomFileScanner should do and keep the test of the of the empty method (with a name that indicates that there is no expected behavior of the default implementation)
  2. Enforce some sort of contract by setting a return type and/or an exception type to registerCustomFileScanner

My preference goes for option 2 because it enables us to write a test where we can implement a child class and test what the default behavior is.

@Test
void registerCustomFileScanner_default_implementation_returns_expected_value() {
  class Child extends CheckRegistrar.RegistrarContext {
    // Nothing overridden here
  }
  var context = new Child();
  assertThat(context.registerCustomFileScanner(null, null)).isEqualTo(EXPECTED_VALUE);
}

@kaufco kaufco force-pushed the marco/SONARCH-708 branch from c20a76d to e486513 Compare April 25, 2025 15:20
@kaufco kaufco force-pushed the marco/SONARCH-708 branch from e486513 to e3731be Compare April 25, 2025 15:32
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

Successfully merging this pull request may close these issues.

2 participants