Skip to content
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 @@ -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 @@ -168,4 +168,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