Skip to content

Commit

Permalink
Implement analyzer for wizards-and-warriors (#145)
Browse files Browse the repository at this point in the history
* Implement analyzer for wizards-and-warriors

* Fixing smoke tests

* Making WizardsAndWarriorsClassAnalyzer static

* Apllying suggestion to make analyzer that checks for override annotation more sophisticated
Adding extra analyzer and scenario to test that
  • Loading branch information
manumafe98 authored Mar 27, 2024
1 parent addcf0c commit c2628d8
Show file tree
Hide file tree
Showing 24 changed files with 652 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 @@ -10,6 +10,7 @@
import analyzer.exercises.needforspeed.NeedForSpeedAnalyzer;
import analyzer.exercises.secrets.SecretsAnalyzer;
import analyzer.exercises.twofer.TwoferAnalyzer;
import analyzer.exercises.wizardsandwarriors.WizardsAndWarriorsAnalyzer;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -57,6 +58,7 @@ private static List<Analyzer> createAnalyzers(String slug) {
case "need-for-speed" -> analyzers.add(new NeedForSpeedAnalyzer());
case "secrets" -> analyzers.add(new SecretsAnalyzer());
case "two-fer" -> analyzers.add(new TwoferAnalyzer());
case "wizards-and-warriors" -> analyzers.add(new WizardsAndWarriorsAnalyzer());
}

return List.copyOf(analyzers);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package analyzer.exercises.wizardsandwarriors;

import analyzer.Comment;

/**
* @see <a href="https://github.com/exercism/website-copy/blob/main/analyzer-comments/java/wizards-and-warriors/use_override_annotation.md">Markdown Template</a>
*/
class UseOverrideAnnotation extends Comment {

@Override
public String getKey() {
return "java.wizards-and-warriors.use_override_annotation";
}

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

import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

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

/**
* The {@link WizardsAndWarriorsAnalyzer} is the analyzer implementation for the {@code wizards-and-warriors} practice exercise.
* It has a subclass WizardsAndWarriorsClassAnalyzer that extends 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/wizards-and-warriors">The wizards-and-warriors exercise on the Java track</a>
*/
public class WizardsAndWarriorsAnalyzer implements Analyzer {
private static final String EXERCISE_NAME = "Wizards and Warriors";
private static final String TO_STRING = "toString";
private static final String IS_VULNERABLE = "isVulnerable";
private static final String GET_DAMAGE_POINTS = "getDamagePoints";

@Override
public void analyze(Solution solution, OutputCollector output) {
var wizardsAndWarriorsClassAnalyzer = new WizardsAndWarriorsClassAnalyzer();

for (var compilationUnit : solution.getCompilationUnits()) {
compilationUnit.getClassByName("Wizard").ifPresent(c -> c.accept(wizardsAndWarriorsClassAnalyzer, output));
compilationUnit.getClassByName("Warrior").ifPresent(c -> c.accept(wizardsAndWarriorsClassAnalyzer, output));
}

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

static class WizardsAndWarriorsClassAnalyzer extends VoidVisitorAdapter<OutputCollector> {

@Override
public void visit(LineComment node, OutputCollector output) {
if (node.getContent().contains("TODO")) {
output.addComment(new RemoveTodoComments());
}

super.visit(node, output);
}

@Override
public void visit(MethodDeclaration node, OutputCollector output) {
if (itsOverridedMethod(node) && doesNotHaveOverrideAnnotation(node)) {
output.addComment(new UseOverrideAnnotation());
}

super.visit(node, output);
}

private static boolean doesNotHaveOverrideAnnotation(MethodDeclaration node) {
return node.findAll(AnnotationExpr.class).isEmpty();
}

private static boolean itsOverridedMethod(MethodDeclaration node) {
return node.getNameAsString().equals(TO_STRING) || node.getNameAsString().equals(IS_VULNERABLE) || node.getNameAsString().equals(GET_DAMAGE_POINTS);
}
}
}
15 changes: 15 additions & 0 deletions src/test/java/analyzer/AnalyzerIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,19 @@ void secrets(String scenario) throws IOException {

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

@ParameterizedTest
@ValueSource(strings = {
"ExemplarSolution",
"ExemplarSolutionWithTodoComments",
"NotUsingOverrideAnnotations",
"UsingAditionalEqualsMethodOverrided"
})
void wizardsandwarriors(String scenario) throws IOException {
var path = Path.of("wizards-and-warriors", scenario + ".java");
var solution = new SolutionFromFiles("wizards-and-warriors", 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": "Wizards and Warriors"
},
"type": "celebratory"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"comments": [
{
"comment": "java.general.remove_todo_comments",
"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.wizards-and-warriors.use_override_annotation",
"params": {},
"type": "informative"
},
{
"comment": "java.general.feedback_request",
"params": {},
"type": "informative"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"comments": [
{
"comment": "java.general.exemplar",
"params": {
"exerciseName": "Wizards and Warriors"
},
"type": "celebratory"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package scenarios.wizardsandwarriors;

class Fighter {

boolean isVulnerable() {
return true;
}

int getDamagePoints(Fighter fighter) {
return 1;
}
}

class Warrior extends Fighter {

@Override
public String toString() {
return "Fighter is a Warrior";
}

@Override
public boolean isVulnerable() {
return false;
}

@Override
int getDamagePoints(Fighter target) {
return target.isVulnerable() ? 10 : 6;
}
}

class Wizard extends Fighter {

boolean isSpellPrepared = false;

@Override
public String toString() {
return "Fighter is a Wizard";
}

@Override
boolean isVulnerable() {
return !isSpellPrepared;
}

@Override
int getDamagePoints(Fighter target) {
return isSpellPrepared ? 12 : 3;
}

void prepareSpell() {
isSpellPrepared = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package scenarios.wizardsandwarriors;

class Fighter {

boolean isVulnerable() {
return true;
}

int getDamagePoints(Fighter fighter) {
return 1;
}
}

// TODO: define the Warrior class
class Warrior extends Fighter {

@Override
public String toString() {
return "Fighter is a Warrior";
}

@Override
public boolean isVulnerable() {
return false;
}

@Override
int getDamagePoints(Fighter target) {
return target.isVulnerable() ? 10 : 6;
}
}

// TODO: define the Wizard class
class Wizard extends Fighter {

boolean isSpellPrepared = false;

@Override
public String toString() {
return "Fighter is a Wizard";
}

@Override
boolean isVulnerable() {
return !isSpellPrepared;
}

@Override
int getDamagePoints(Fighter target) {
return isSpellPrepared ? 12 : 3;
}

void prepareSpell() {
isSpellPrepared = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package scenarios.wizardsandwarriors;

class Fighter {

boolean isVulnerable() {
return true;
}

int getDamagePoints(Fighter fighter) {
return 1;
}
}

class Warrior extends Fighter {

public String toString() {
return "Fighter is a Warrior";
}

public boolean isVulnerable() {
return false;
}

int getDamagePoints(Fighter target) {
return target.isVulnerable() ? 10 : 6;
}
}

class Wizard extends Fighter {

boolean isSpellPrepared = false;

public String toString() {
return "Fighter is a Wizard";
}

boolean isVulnerable() {
return !isSpellPrepared;
}

int getDamagePoints(Fighter target) {
return isSpellPrepared ? 12 : 3;
}

void prepareSpell() {
isSpellPrepared = true;
}
}
Loading

0 comments on commit c2628d8

Please sign in to comment.