Skip to content

Commit

Permalink
Implement analyzer for salary-calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
manumafe98 committed Mar 28, 2024
1 parent 054f556 commit 9745415
Show file tree
Hide file tree
Showing 36 changed files with 738 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/main/java/analyzer/AnalyzerRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import analyzer.exercises.leap.LeapAnalyzer;
import analyzer.exercises.loglevels.LogLevelsAnalyzer;
import analyzer.exercises.needforspeed.NeedForSpeedAnalyzer;
import analyzer.exercises.salarycalculator.SalaryCalculatorAnalyzer;
import analyzer.exercises.secrets.SecretsAnalyzer;
import analyzer.exercises.twofer.TwoferAnalyzer;
import analyzer.exercises.wizardsandwarriors.WizardsAndWarriorsAnalyzer;
Expand Down Expand Up @@ -56,6 +57,7 @@ private static List<Analyzer> createAnalyzers(String slug) {
case "leap" -> analyzers.add(new LeapAnalyzer());
case "log-levels" -> analyzers.add(new LogLevelsAnalyzer());
case "need-for-speed" -> analyzers.add(new NeedForSpeedAnalyzer());
case "salary-calculator" -> analyzers.add(new SalaryCalculatorAnalyzer());
case "secrets" -> analyzers.add(new SecretsAnalyzer());
case "two-fer" -> analyzers.add(new TwoferAnalyzer());
case "wizards-and-warriors" -> analyzers.add(new WizardsAndWarriorsAnalyzer());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package analyzer.exercises.salarycalculator;

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

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

/**
* The {@link SalaryCalculatorAnalyzer} is the analyzer implementation for the {@code salary-calculator} 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/salary-calculator">The salary-calculator exercise on the Java track</a>
*/
public class SalaryCalculatorAnalyzer extends VoidVisitorAdapter<OutputCollector> implements Analyzer {
private static final String EXERCISE_NAME = "Salary Calculator";
private static final String SALARY_MULTIPLIER = "salaryMultiplier";
private static final String BONUS_MULTIPLIER = "bonusMultiplier";
private static final String FINAL_SALARY = "finalSalary";
private static final String BONUS_FOR_PRODUCTS_SOLD = "bonusForProductsSold";
private boolean essentialCommentAdded = false;

@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 (!essentialCommentAdded && isMethodThatMustContainTernaryOperators(node) && doesNotHasTernaryOperators(node)) {
output.addComment(new UseTernaryOperators(node.getNameAsString()));
essentialCommentAdded = true;
}

if (!essentialCommentAdded && node.getNameAsString().equals(BONUS_FOR_PRODUCTS_SOLD) && doesNotCallMethod(node, BONUS_MULTIPLIER)) {
output.addComment(new ReuseCode(BONUS_FOR_PRODUCTS_SOLD, BONUS_MULTIPLIER));
}

if (!essentialCommentAdded && node.getNameAsString().equals(FINAL_SALARY) && doesNotCallMethod(node, SALARY_MULTIPLIER)) {
output.addComment(new ReuseCode(FINAL_SALARY, SALARY_MULTIPLIER));
}

if (!essentialCommentAdded && node.getNameAsString().equals(FINAL_SALARY) && doesNotCallMethod(node, BONUS_FOR_PRODUCTS_SOLD)) {
output.addComment(new ReuseCode(FINAL_SALARY, BONUS_FOR_PRODUCTS_SOLD));
}

super.visit(node, output);
}

private static boolean isMethodThatMustContainTernaryOperators(MethodDeclaration node) {
return node.getNameAsString().equals(SALARY_MULTIPLIER) || node.getNameAsString().equals(BONUS_MULTIPLIER) || node.getNameAsString().equals(FINAL_SALARY);
}

private static boolean doesNotHasTernaryOperators(MethodDeclaration node) {
return node.findAll(ConditionalExpr.class).isEmpty();
}

private static boolean doesNotCallMethod(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,32 @@
package analyzer.exercises.salarycalculator;

import java.util.Map;

import analyzer.Comment;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/salary-calculator/use_ternary_operators.md">Markdown Template</a>
*/
class UseTernaryOperators extends Comment {
private final String inMethod;

public UseTernaryOperators(String inMethod) {
this.inMethod = inMethod;
}

@Override
public String getKey() {
return "java.salary-calculator.use_ternary_operators";
}

@Override
public Map<String, String> getParameters() {
return Map.of(
"inMethod", this.inMethod);
}

@Override
public Type getType() {
return Type.ESSENTIAL;
}
}
21 changes: 21 additions & 0 deletions src/test/java/analyzer/AnalyzerIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,25 @@ void wizardsandwarriors(String scenario) throws IOException {

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

@ParameterizedTest
@ValueSource(strings = {
"ExemplarSolution",
"NoReuseBonusForProductsSold",
"NoReuseBonusMultiplier",
"NoReuseSalaryMultiplier",
"NotReusingMethodsAtAll",
"NotUsingTernaryOperatorsAndNotReusingMethods",
"NotUsingTernaryOperatorsAtAll",
"NotUsingTernaryOperatorsOnBonusMultiplier",
"NotUsingTernaryOperatorsOnFinalSalary",
"NotUsingTernaryOperatorsOnSalaryMultiplier"
})
void salarycalculator(String scenario) throws IOException {
var path = Path.of("salary-calculator", scenario + ".java");
var solution = new SolutionFromFiles("salary-calculator", 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
@@ -0,0 +1,11 @@
{
"comments": [
{
"comment": "java.general.exemplar",
"params": {
"exerciseName": "Salary Calculator"
},
"type": "celebratory"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "bonusForProductsSold"
},
"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": "bonusForProductsSold",
"methodToCall": "bonusMultiplier"
},
"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": "finalSalary",
"methodToCall": "salaryMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"comments": [
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "bonusForProductsSold",
"methodToCall": "bonusMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "salaryMultiplier"
},
"type": "actionable"
},
{
"comment": "java.general.reuse_code",
"params": {
"callingMethod": "finalSalary",
"methodToCall": "bonusForProductsSold"
},
"type": "actionable"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "bonusMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "finalSalary"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": [
{
"comment": "java.salary-calculator.use_ternary_operators",
"params": {
"inMethod": "salaryMultiplier"
},
"type": "essential"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package scenarios.salarycalculator;

public class SalaryCalculator {

public double salaryMultiplier(int daysSkipped) {
return daysSkipped < 5 ? 1 : 0.85;
}

public int bonusMultiplier(int productsSold) {
return productsSold < 20 ? 10 : 13;
}

public double bonusForProductsSold (int productsSold) {
return productsSold * bonusMultiplier(productsSold);
}

public double finalSalary (int daysSkipped, int productsSold) {
double finalSalary = 1000.0 * salaryMultiplier(daysSkipped) + bonusForProductsSold(productsSold);
return finalSalary > 2000.0 ? 2000.0 : finalSalary;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package scenarios.salarycalculator;

public class SalaryCalculator {

public double salaryMultiplier(int daysSkipped) {
return daysSkipped < 5 ? 1 : 0.85;
}

public int bonusMultiplier(int productsSold) {
return productsSold < 20 ? 10 : 13;
}

public double bonusForProductsSold (int productsSold) {
return productsSold * bonusMultiplier(productsSold);
}

public double finalSalary (int daysSkipped, int productsSold) {
double finalSalary = 1000.0 * salaryMultiplier(daysSkipped) + productsSold * bonusMultiplier(productsSold);
return finalSalary > 2000.0 ? 2000.0 : finalSalary;
}
}
Loading

0 comments on commit 9745415

Please sign in to comment.