I am very new to Sonar.
I am trying to make my own plugin for sonar. After downloading plugin example, I make it eclipse ready using mvn eclipse:eclipse and import to workspace. It is compiling fine.
But I need to add my own Rule files to it.
For that purpose, I have created 2 files.
MyCustomNLSRuleTest .java
package org.sonar.samples.java.checks;
import org.junit.Test;
import org.sonar.java.checks.verifier.JavaCheckVerifier;
public class MyCustomNLSRuleTest {
#Test
public void check() {
// Verifies that the check will raise the adequate issues with the expected message.
// In the test file, lines which should raise an issue have been commented out
// by using the following syntax: "// Noncompliant {{EXPECTED_MESSAGE}}"
JavaCheckVerifier.verify("src/test/files/MissingCheck.java", new MyCustomSubscriptionRule());
}
}
The actual rule is provided to me in the following java file which looks like below -
MissingCheck.java
public class MissingCheck extends Check
{
private HashMap<Integer, Integer> lineStringMap;
#Override
public void beginTree(DetailAST aRootAST) {
super.beginTree(aRootAST);
lineStringMap = new HashMap<>();
}
#Override
public int[] getDefaultTokens() {
return new int[] { TokenTypes.STRING_LITERAL};
}
#Override
public void visitToken(DetailAST ast) {
DetailAST parent = ast.getParent();
if (parent != null) {
DetailAST grandpa = parent.getParent();
if (isAnnotation(grandpa.getType())) {
return;
}
}
Integer count = lineStringMap.get(ast.getLineNo());
if (count == null) {
count = new Integer(1);
} else {
count++;
}
FileContents contents = getFileContents();
String[] line = contents.getLines();
if (line.length >= ast.getLineNo()) {
String l = line[ast.getLineNo() - 1];
if (!l.contains("$NON-NLS-" + count + "$")) {
log(ast.getLineNo(), "String_Not_Externalized", new Object[] { ast.getText() });
}
}
lineStringMap.put(ast.getLineNo(), count);
}
/**
* Checks if type is an annotation.
* #param type to check
* #return <code>true</code> if type is an annotation.
*/
private boolean isAnnotation(int type) {
return (type >= TokenTypes.ANNOTATION_DEF && type <= TokenTypes.ANNOTATION_ARRAY_INIT);
}
}
But, I am trying to do mvn clean package this project, it gives me error:
Results :
Tests in error:
MyCustomNLSRuleTest.check:13 ยป IllegalState At least one issue expected
Tests run: 8, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ---------------------------------------------------------------------
Any idea, how I can add a new rule in the plugin?
Thanks!
Okay, it seems that you are very far from what you are supposed to do when writing custom rules for the java plugin... A few questions first:
Did you actually tried to have a look at the dedicated page from the SonarQube confluence? http://docs.sonarqube.org/display/DEV/Custom+Rules+for+Java
Did you actually look at the following links before trying to write a rule?
The rule already implemented in the example project,
How they are tested,
With which test files,
How they are registered in the custom plugin,
The comments from the unit test you are actually writing.
Now... Let's start by explaining to you what you are currently doing, as apparently it's not clear at all.
You created a test file called MyCustomNLSRuleTest.java, which should theoretically correspond to a rule called MyCustomNLSRule. Note that it's probably not the case, as you are saying that the rule is provided to you in the MissingCheck.java file.
Your unit test uses JavaCheckVerifier to verify that the file provided as argument, "src/test/files/MissingCheck.java", will raise all the expected issues when playing the rule MyCustomSubscriptionRule against it.
At this point, you are not testing at all your MissingCheck, but using it as data for the MyCustomSubscriptionRule rule... And it's probably your main issue.
However, if this is actually really what you are trying to achieve, it means that:
You modified the rule MyCustomSubscriptionRule to have a custom behavior, different from the one from the original example project.
When executing it on the file MissingCheck.java, the check is supposed to raise issue (with the line having issue being commented out with // Noncompliant {{expected message}})
Your custom rule does not work, as it apparently raised no issue at all when playing the test.
Please look at all the links provided above to see how custom rules works, what is available in the java plugin API, and what you can achieve with it.
Related
Due to project requirement we need to import the project mappings & other objects from a different server. But we found that all the mapping context becomes undefined.
I am trying to write a groovy program to set the context at a bulk. I have written the below code but somehow the interfaceList is empty and thus unable to perform odiInterface.setOptimizationContext(context);.
Below is my code. For brevity I haven't mentioned the packages stmt.
def all the variables like url,driver,schema etc
def all variables like MasterInfo, auth, transaction, etc
def OdiContext context = ((IOdiContextFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiContext.class)).findByCode("CTX_ANN1_S4")
for (p in odiProjectList) {
if (p.getName() == "PrjDemo_TA") {
def OdiFolderList = p.getFolders()
for (f in OdiFolderList) {
if (f.getName() == "TrgDemoMod_Comn_TA_S4") {
// def OdiInterfaceList2 = f.getInterfaces()
// def OdiMappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
def OdiInterfaceList = ((IOdiInterfaceFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiInterface.class)).findByProject(projectCode, folderName)
for (m in OdiInterfaceList2) {
println(m.getName() + "|" + m.getClass()) //+ "|" + m.getParent() + "|" + m.getFolder() )
m.setOptimizationContext(context)
}
tm.commit(txnStatus)
}
}
}
}
The line which initializes OdiInterfaceList is not throwing any error nor populating desired interface lists of all the interfaces within a folder.
So m.setOptimizationContext(context) is not executed.
If i substitute that line with:
def OdiMappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
within a for ... loop i can able to access the mappings but I don't know how to set its context OdiMappingList as setOptimizationContext is an interface's method.
I'm unable to reproduce your case as I don't have the environment to test it, but I still think I can help.
First, I refactored your code so its more groovy:
def OdiContext context = ((IOdiContextFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiContext.class)).findByCode("CTX_ANN1_S4")
// Looking for the project
def prjDemo = odiProjectList.find { it.name == "PrjDemo_TA" }
assert prjDemo : "Unable to find ODI project"
//Getting the Mappings
def mappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
assert ! mappingList.toList().empty : "Mappings not found"
// Printing interfaces
mappingList.each {
it.setDefaultContext(context as IContext)
}
With those asserts, you may be able to know more in detail where your code may be really failing.
I noticed that IOdiInterfaceFinder is marked as deprecated, so it might not play well with Oracle 12c. Check your versions.
Probably it would be better if you try to replace that deprecated code with a more updated version. I found some similar code to yours in this page, so it might be useful.
UPDATE:
Updated the code to use Mapping class. As it has setDefaultContext(IContext ctx) method and OdiContext implements IContext, maybe it might work.
Is there a command line tool that can automatically fix non formatting but still seemingly simple CheckStyle issues in Java source code like:
Avoid inline conditionals
Make "xxx" a static method
I know there are various tools to fix formatting and some IDEs have fairly advanced quick fixers but so far I could not find anything that can recursively run on a source code folder or be integrated in a commit hook.
Sounds like a nice challenge, but I was also unable to find an automatic tool that can do this. As you already described, there are plenty of options to change code formatting. For other small issues, you could perhaps run Checkstyle from the command-line and filter out fixable warnings. A library for parsing and changing Java source code could help to actually make the changes, like for example JavaParser. Perhaps you could write a custom tool in a relatively small amount of time using a Java source code manipulation tool like JavaParser.
(There are other tools like ANTLR that could be used; see for more ideas this question on Stack Overflow: Java: parse java source code, extract methods. Some libraries like Roaster and JavaPoet do not parse the body of methods, which makes them less suitable in this situation.)
As a very simple example, assume we have a small Java class for which Checkstyle generates two messages (with a minimalistic checkstyle-checks.xml Checkstyle configuration file that only checks FinalParameters and FinalLocalVariable):
// Example.java:
package q45326752;
public class Example {
public static void main(String[] arguments) {
System.out.println("Hello Checkstyle...");
int perfectNumber = 1 + 2 + 3;
System.out.println("Perfect number: " + perfectNumber);
}
}
Checkstyle warnings:
java -jar checkstyle-8.0-all.jar -c checkstyle-checks.xml Example.java
[ERROR] Example.java:4:29: Parameter arguments should be final. [FinalParameters]
[ERROR] Example.java:7:13: Variable 'perfectNumber' should be declared final. [FinalLocalVariable]
Using JavaParser, these two warnings could be fixed automatically like this (the code tries to demonstrate the idea; some parts have been ignored for now):
// AutomaticCheckstyleFix.java:
package q45326752;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import java.io.File;
import java.io.FileNotFoundException;
public class AutomaticCheckstyleFix {
private MethodDeclaration bestMatchMethod;
private int bestMatchMethodLineNumber;
private Statement statementByLineNumber;
public static void main(final String[] arguments) {
final String filePath = "q45326752\\input\\Example.java";
try {
new AutomaticCheckstyleFix().fixSimpleCheckstyleIssues(new File(filePath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private void fixSimpleCheckstyleIssues(File file) throws FileNotFoundException {
CompilationUnit javaClass = JavaParser.parse(file);
System.out.println("Original Java class:\n\n" + javaClass);
System.out.println();
System.out.println();
// Example.java:4:29: Parameter arguments should be final. [FinalParameters]
MethodDeclaration methodIssue1 = getMethodByLineNumber(javaClass, 4);
if (methodIssue1 != null) {
methodIssue1.getParameterByName("arguments")
.ifPresent(parameter -> parameter.setModifier(Modifier.FINAL, true));
}
// Example.java:7:13: Variable 'perfectNumber' should be declared final.
// [FinalLocalVariable]
Statement statementIssue2 = getStatementByLineNumber(javaClass, 7);
if (statementIssue2 instanceof ExpressionStmt) {
Expression expression = ((ExpressionStmt) statementIssue2).getExpression();
if (expression instanceof VariableDeclarationExpr) {
((VariableDeclarationExpr) expression).addModifier(Modifier.FINAL);
}
}
System.out.println("Modified Java class:\n\n" + javaClass);
}
private MethodDeclaration getMethodByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
bestMatchMethod = null;
javaClass.getTypes().forEach(type -> type.getMembers().stream()
.filter(declaration -> declaration instanceof MethodDeclaration)
.forEach(method -> {
if (method.getTokenRange().isPresent()) {
int methodLineNumber = method.getTokenRange().get()
.getBegin().getRange().begin.line;
if (bestMatchMethod == null
|| (methodLineNumber < issueLineNumber
&& methodLineNumber > bestMatchMethodLineNumber)) {
bestMatchMethod = (MethodDeclaration) method;
bestMatchMethodLineNumber = methodLineNumber;
}
}
})
);
return bestMatchMethod;
}
private Statement getStatementByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
statementByLineNumber = null;
MethodDeclaration method = getMethodByLineNumber(javaClass, issueLineNumber);
if (method != null) {
method.getBody().ifPresent(blockStmt
-> blockStmt.getStatements().forEach(statement
-> statement.getTokenRange().ifPresent(tokenRange -> {
if (tokenRange.getBegin().getRange().begin.line == issueLineNumber) {
statementByLineNumber = statement;
}
})));
}
return statementByLineNumber;
}
}
Another approach could be to create new Checkstyle plugins based on the ones you are trying to create an automatic fix for. Perhaps you have enough information available to not only give a warning but to also generate a modified version with these issues fixed.
Personally I would hesitate to have issues fixed automatically upon commit. When there are many simple fixes to be made, automation is welcome, but I would like to check these changes before committing them. Running a tool like this and checking the changes could be a very fast way to fix a lot of simple issues.
Some checks that I think could be fixed automatically:
adding static
fixing inline conditionals
FinalParameters and FinalLocalVariable: adding final
ModifierOrder: reordering modifiers (example: final static private)
NeedBraces: adding braces
I'm working on a maven project. The scenario is something like below...
class Test {
public void applyAll() {
....................
....................
Collection<Migratable> applicableUpdates = SomeOtherClass.getApplicableUpdates();
doUpdate(applicableUpdates);
}
#Benchmark
public void apply(Migratable m) {
....................
....................
}
private void doUpdate(Collection<Migratable> applicableUpdates) throws Exception {
for (Migratable m : applicableUpdates) {
try {
apply(m);
} catch (Exception e) {
logger.error("Falid to apply migration {}" + m, e);
throw e;
}
}
}
}
I need to compute how long it takes to execute each migration. Simply I need to compute the execution time of apply(Migratable m) method.
Now, when I build my project using "mvn clean install", build failed and it shows "Method parameters should be #State classes".
Here, parameter comes from another method doUpdate(Collection applicableUpdates) [see the scenario]. So how can I get rid of this error in given scenario?
There are quite a few problems in your setup here and it seems you haven't actually looked at the samples of JMH; and I strongly advise you to do that.
A few notes...
1) You #Benchmark method returns void - it should return something; otherwise use BlackHoles (this is in the samples).
2) If parameters comes from another method it means that method should be a #SetUp method (this is in the samples)
3) The error that you are seeing has to do with the fact that your Migratable is not actually a #State class (this is again in the samples!)
At this point I can't stress that enough - but look and understand the samples. It's not going to be easy, this is micro-benchmark and as much as JMH tries to make things easier for us by hiding all the very complicated code, it still requires us to conform to the rules that exist there.
i am using eclemma and trying to increase my test coverage:
so far this is my code:
public RolesResponse findRolesByTenant(RolesRequest rolesRequest)
{
RolesResponse rolesResponse = new RolesResponse();
List<Role> roleList = null;
if (StringUtils.isNotBlank(rolesRequest.getTenantCode()))
{
roleList = roleFunctionService.getAllRolesAndFunctionsByTenant(rolesRequest.getTenantCode());
}
if (CollectionUtils.isNotEmpty(roleList))
{
rolesResponse.setRoles(roleList);
}
else
{
rolesResponse.setError(LayerContextHolder.getErrorObject());
}
return rolesResponse;
}
and here is my test:
#Test
public void findRolesByTenantTest()
{
RolesRequest rolesRequest = new RolesRequest();
rolesRequest.setTenantCode("test");
ErrorObject errorObject = new ErrorObject();
RolesResponse rolesResponse = rolesProcessService.findRolesByTenant(rolesRequest);
Assert.assertNull(rolesResponse.getError());
}
the only line eclemma is highlighting in red is this one:
rolesResponse.setError(LayerContextHolder.getErrorObject());
can someone help me in constructing the final test needed to cover this line
thanks
I'm really not a fan of your test anyway - what are you trying to prove by the error being null? That the list came back with something? Also, are you certain that your service will return the result you want in your test every single time?
Don't think of tests in terms of coverage; this will lead to brittle tests and tests that give a false sense of security. What you want to do is write tests that cover each condition that the code could encounter, and the line coverage can follow from that.
From your code, I see two cases.
roleFunctionService#getAllRolesByFunctionAndTenant can return a non-empty list.
It's implied that the resultant rolesResponse#roles contains whatever was in the list provided by the method, and this should be verified.
It's also implied that there is no error set on the object, so it should be null.
roleFunctionService#getAllRolesByFunctionAndTenant can return an empty list
Either the resultant rolesResponse#roles are empty or null; it'd be better if it were empty.
It's implied that there is an error on the object, which is specifically provided by LayerContextHolder.getErrorObject(). You should check to see that it's exactly that.
You'll get to the whole approach of writing this test through the use of a mocking framework.
I'm currently having a problem with a Unit test using EasyMock.
Expectation failure on verify:
FileConverter.convert(file, file2): expected: 1, actual: 1
This is the only failure in the class and it fails on the verify method below. I have tried to Google the message, but this only brings up results for "expected: 1, actual: 1 (+1)", and the +1 implies the error is different.
I have tried to simplify the structure of the failing EasyMock test for demonstration. Please forgive any typos:
#Test
public void testScan() {
String[] testFiles = { "file", "file2" };
FileConverter converterMock = EasyMock.createMock(FileConverter.class);
Poller poller = new Poller(new File("testFolder"), converterMock);
for (String testFile : testFiles) {
converterMock.convert(new File(testFile));
EasyMock.expectLastCall().once();
}
EasyMock.replay(converterMock);
for (String testFile : testFiles) {
poller.scan();
}
EasyMock.verify(converterMock);
}
I don't think the code itself is particularly relevant but I have included it for completeness - what I am really looking for is an explanation of what "expected 1, actual 1" could mean in the context of the EasyMock.verify method.
Thanks in advance!
Another optional case is when using a multithreaded environment, it might occur that the desired method has invoked on the mock object after the test has already ended.
Error messages can be very unclear from these test runs. I do see it fails on expecting a convert method call signature with 2 File arguments. So try expecting that by completing/replacing the following line in your test:
converterMock.convert(new File(testFile));
with something like:
File file1 = new File(testFile1);
File file2 = new File(testFile2);
converterMock.convert(testFile1, testFile2);
Also experiment with less specific matching like:
converterMock.convert(EasyMock.isA(File.class), EasyMock.isA(File.class));
or
File file1 = new File(testFile1);
File file2 = new File(testFile2);
converterMock.convert(EasyMock.eq(file1), EasyMock.eq(file2));
Are you using a recent version of EasyMock? Because I do remember old version performing strange calculation sometimes.
I tried your code and if I guessed correctly the content of the scan method.
void scan(String file) {
converter.convert(new File(file));
}
It should work perfectly.