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

Adding analyzer for log-levels concept exercise #136

Merged
merged 8 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/analyzer/AnalyzerRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import analyzer.exercises.hamming.HammingAnalyzer;
import analyzer.exercises.lasagna.LasagnaAnalyzer;
import analyzer.exercises.leap.LeapAnalyzer;
import analyzer.exercises.loglevels.LogLevelsAnalyzer;
import analyzer.exercises.needforspeed.NeedForSpeedAnalyzer;
import analyzer.exercises.twofer.TwoferAnalyzer;

Expand Down Expand Up @@ -51,6 +52,7 @@ private static List<Analyzer> createAnalyzers(String slug) {
case "hamming" -> analyzers.add(new HammingAnalyzer());
case "lasagna" -> analyzers.add(new LasagnaAnalyzer());
case "leap" -> analyzers.add(new LeapAnalyzer());
case "log-levels" -> analyzers.add(new LogLevelsAnalyzer());
case "need-for-speed" -> analyzers.add(new NeedForSpeedAnalyzer());
case "two-fer" -> analyzers.add(new TwoferAnalyzer());
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/analyzer/comments/PreferStringConcatenation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package analyzer.comments;

import analyzer.Comment;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/general/prefer_string_concatenation.md">Markdown Template</a>
*/
public class PreferStringConcatenation extends Comment {

@Override
public String getKey() {
return "java.general.prefer_string_concatenation";
}

@Override
public Type getType() {
return Type.INFORMATIVE;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package analyzer.exercises.lasagna;
package analyzer.comments;

import analyzer.Comment;

import java.util.Map;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/lasagna/reuse_code.md">Markdown Template</a>
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/general/reuse_code.md">Markdown Template</a>
*/
class ReuseCode extends Comment {
public class ReuseCode extends Comment {
private final String callingMethod;
private final String methodToCall;

ReuseCode(String callingMethod, String methodToCall) {
public ReuseCode(String callingMethod, String methodToCall) {
this.callingMethod = callingMethod;
this.methodToCall = methodToCall;
}

@Override
public String getKey() {
return "java.lasagna.reuse_code";
return "java.general.reuse_code";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import analyzer.Solution;
import analyzer.comments.ExemplarSolution;
import analyzer.comments.RemoveTodoComments;
import analyzer.comments.ReuseCode;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.LineComment;
Expand Down
manumafe98 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package analyzer.exercises.loglevels;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.expr.StringLiteralExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import analyzer.Analyzer;
import analyzer.OutputCollector;
import analyzer.Solution;
import analyzer.comments.AvoidHardCodedTestCases;
import analyzer.comments.ExemplarSolution;
import analyzer.comments.PreferStringConcatenation;
import analyzer.comments.ReuseCode;

import java.util.List;

/**
* The {@link LogLevelsAnalyzer} is the analyzer implementation for the {@code log-levels} practice exercise.
* It extends from the {@link VoidVisitorAdapter} and uses the visitor pattern to traverse each compilation unit.
*
* @see <a href="https://github.com/exercism/java/tree/main/exercises/concept/log-levels">The log-levels exercise on the Java track</a>
*/
public class LogLevelsAnalyzer extends VoidVisitorAdapter<OutputCollector> implements Analyzer {
private static final String EXERCISE_NAME = "Log Levels";
private static final String REFORMAT = "reformat";
private static final String MESSAGE = "message";
private static final String LOG_LEVEL = "logLevel";
private static final String SUBSTRING = "substring";
private static final String FORMAT = "format";

@Override
public void analyze(Solution solution, OutputCollector output) {
for (CompilationUnit compilationUnit : solution.getCompilationUnits()) {
compilationUnit.accept(this, output);
}

if (output.getComments().isEmpty()) {
output.addComment(new ExemplarSolution(EXERCISE_NAME));
}
}

@Override
public void visit(MethodDeclaration node, OutputCollector output) {
if (containsHarcodedString(node)) {
output.addComment(new AvoidHardCodedTestCases());
return;
}

if (!node.getNameAsString().equals(REFORMAT) && doesNotCallMethod(node, SUBSTRING)) {
output.addComment(new UseSubstringMethod());
return;
}

if (node.getNameAsString().equals(REFORMAT) && doesNotCallMethod(node, MESSAGE)) {
output.addComment(new ReuseCode(REFORMAT, MESSAGE));
}

if (node.getNameAsString().equals(REFORMAT) && doesNotCallMethod(node, LOG_LEVEL)) {
output.addComment(new ReuseCode(REFORMAT, LOG_LEVEL));
}

if (node.getNameAsString().equals(REFORMAT) && callsMethod(node, FORMAT)) {
output.addComment(new PreferStringConcatenation());
}

super.visit(node, output);
}

private static boolean containsHarcodedString(MethodDeclaration node) {
List<StringLiteralExpr> hardcodedStrings = node.findAll(StringLiteralExpr.class,
x -> x.getValue().contains("ERROR") || x.getValue().contains("WARNING")
|| x.getValue().contains("INFO"));

return hardcodedStrings.size() > 1;
}

private static boolean doesNotCallMethod(MethodDeclaration node, String otherMethodName) {
return node.findAll(MethodCallExpr.class, x -> x.getNameAsString().contains(otherMethodName)).isEmpty();
}

private static boolean callsMethod(MethodDeclaration node, String otherMethodName) {
return !node.findAll(MethodCallExpr.class, x -> x.getNameAsString().contains(otherMethodName)).isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package analyzer.exercises.loglevels;

import analyzer.Comment;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/log-levels/use_substring_method.md">Markdown Template</a>
*/
class UseSubstringMethod extends Comment {

@Override
public String getKey() {
return "java.log-levels.use_substring_method";
}

@Override
public Type getType() {
return Type.ACTIONABLE;
}
}
24 changes: 22 additions & 2 deletions src/test/java/analyzer/AnalyzerIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void annalynsinfiltration(String scenario) throws IOException {

Approvals.verify(serialize(output.analysis()), Approvals.NAMES.withParameters(scenario));
}

@ParameterizedTest
@ValueSource(strings = {
"ExemplarSolution",
Expand All @@ -126,7 +126,27 @@ void needforspeed(String scenario) throws IOException {
var path = Path.of("need-for-speed", scenario + ".java");
var solution = new SolutionFromFiles("need-for-speed", SCENARIOS.resolve(path));
var output = AnalyzerRoot.analyze(solution);


Approvals.verify(serialize(output.analysis()), Approvals.NAMES.withParameters(scenario));
}

@ParameterizedTest
@ValueSource(strings = {
"ExemplarSolution",
"HardCodingLogLevels",
"NoReuseLogLevel",
"NoReuseMessage",
"NoReuseOfBothMethods",
"NotUsingSubstringOnLogLevel",
"NotUsingSubstringOnMessage",
manumafe98 marked this conversation as resolved.
Show resolved Hide resolved
"NotUsingSubstringOnBothMethods",
"UsingStringFormat"
})
void loglevels(String scenario) throws IOException {
var path = Path.of("log-levels", scenario + ".java");
var solution = new SolutionFromFiles("log-levels", SCENARIOS.resolve(path));
var output = AnalyzerRoot.analyze(solution);

Approvals.verify(serialize(output.analysis()), Approvals.NAMES.withParameters(scenario));
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"comments": [
{
"comment": "java.lasagna.reuse_code",
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "remainingMinutesInOven",
"methodToCall": "expectedMinutesInOven"
},
"type": "actionable"
},
{
"comment": "java.lasagna.reuse_code",
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "totalTimeInMinutes",
"methodToCall": "preparationTimeInMinutes"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"comments": [
{
"comment": "java.lasagna.reuse_code",
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "remainingMinutesInOven",
"methodToCall": "expectedMinutesInOven"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"comments": [
{
"comment": "java.lasagna.reuse_code",
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "totalTimeInMinutes",
"methodToCall": "preparationTimeInMinutes"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"comments": [
{
"comment": "java.general.exemplar",
"params": {
"exerciseName": "Log Levels"
},
"type": "celebratory"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comments": [
{
"comment": "java.general.avoid_hard_coded_test_cases",
"params": {},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "reformat",
"methodToCall": "logLevel"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "reformat",
"methodToCall": "message"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "reformat",
"methodToCall": "message"
},
"type": "actionable"
},
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "reformat",
"methodToCall": "logLevel"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comments": [
{
"comment": "java.log-levels.use_substring_method",
"params": {},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comments": [
{
"comment": "java.log-levels.use_substring_method",
"params": {},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comments": [
{
"comment": "java.log-levels.use_substring_method",
"params": {},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Loading