inventory_mock tests #17

Merged
erns6604 merged 16 commits from inventory_mocks into main 2025-10-30 07:52:55 +01:00
23 changed files with 249 additions and 88 deletions

View File

@@ -1,11 +1,11 @@
package Action; package Action;
import Job.HasJob; import Job.JobHolder;
import Job.Wizard; import Job.Wizard;
public class CastAction implements Action { public class CastAction implements Action {
private Wizard requireWizard(Actor actor) { private Wizard requireWizard(Actor actor) {
if (actor instanceof HasJob hasJob && hasJob.getJob() instanceof Wizard wizard) { if (actor instanceof JobHolder hasJob && hasJob.getJob() instanceof Wizard wizard) {
return wizard; return wizard;
} }
throw new IllegalStateException(actor + " cannot perform this action without being a Wizard!"); throw new IllegalStateException(actor + " cannot perform this action without being a Wizard!");

View File

@@ -1,6 +1,6 @@
package Action; package Action;
import Job.HasJob; import Job.JobHolder;
import Job.Miner; import Job.Miner;
import Terrain.Biome; import Terrain.Biome;
@@ -16,8 +16,7 @@ public class DigAction implements Action {
} }
private Miner requireMiner(Actor actor) { private Miner requireMiner(Actor actor) {
if (actor instanceof HasJob hasJob if (actor.getJob() instanceof Miner miner) {
&& hasJob.getJob() instanceof Miner miner) {
return miner; return miner;
} }
throw new IllegalStateException(actor + " cannot perform this action without being a Miner!"); throw new IllegalStateException(actor + " cannot perform this action without being a Miner!");

View File

@@ -1,6 +1,6 @@
package Action; package Action;
import Job.HasJob; import Job.JobHolder;
import Job.Wizard; import Job.Wizard;
public class LearnSpellAction implements Action { public class LearnSpellAction implements Action {
@@ -11,7 +11,7 @@ public class LearnSpellAction implements Action {
} }
private Wizard requireWizard(Actor actor) { private Wizard requireWizard(Actor actor) {
if (actor instanceof HasJob hasJob && hasJob.getJob() instanceof Wizard wizard) { if (actor instanceof JobHolder hasJob && hasJob.getJob() instanceof Wizard wizard) {
return wizard; return wizard;
} }
throw new IllegalStateException(actor + " cannot perform this action without being a Wizard!"); throw new IllegalStateException(actor + " cannot perform this action without being a Wizard!");

View File

@@ -1,7 +0,0 @@
package Character;
import java.util.List;
public interface HasInventory {
List<String> getInventory();
}

View File

@@ -4,7 +4,7 @@ package Entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public abstract class Entity implements HasPosition { public abstract class Entity implements Positionable {
protected String name; protected String name;
protected Position position; protected Position position;
private static final List<Entity> entities = new ArrayList<Entity>(); private static final List<Entity> entities = new ArrayList<Entity>();

View File

@@ -9,15 +9,15 @@ import Combat.Spell;
import Inventory.Inventory; import Inventory.Inventory;
import Item.Equipment; import Item.Equipment;
import Job.Job; import Job.Job;
import Job.HasJob; import Job.JobHolder;
import Inventory.HasInventory; import Inventory.InventoryHolder;
import Inventory.HasSpellBook; import Inventory.HasSpellBook;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class Player extends Entity implements Movable, Actor, HasInventory, HasSpellBook, HasJob, HasHealth, HasMana, HasConditions { public class Player extends Entity implements Movable, Actor, InventoryHolder, HasSpellBook, JobHolder, HasHealth, HasMana, HasConditions {
protected int health; protected int health;
protected int mana; protected int mana;
protected int strength; protected int strength;
@@ -43,6 +43,20 @@ public class Player extends Entity implements Movable, Actor, HasInventory, HasS
super(name); super(name);
} }
public Player(String name, Inventory inventory) {
super(name);
this.inventory = inventory;
this.position = new Position(0,0);
}
public Player(String name, Job job, Inventory inventory) {
super(name);
this.job = job;
this.inventory = inventory;
this.position = new Position(0,0);
}
@Override @Override
public void moveTo(Position position) { public void moveTo(Position position) {
if(canMoveTo(position)){ if(canMoveTo(position)){
@@ -52,7 +66,9 @@ public class Player extends Entity implements Movable, Actor, HasInventory, HasS
@Override @Override
public boolean canMoveTo(Position position) { public boolean canMoveTo(Position position) {
return true; boolean withinX = (position.x() - 2) < this.position.x() && this.position.x() < (position.x() + 2);
boolean withinY = (position.y() - 2) < this.position.y() && this.position.y() < (position.y() + 2);
return withinX && withinY;
} }
public Job getJob() { public Job getJob() {
return job; return job;

View File

@@ -1,6 +1,6 @@
package Entity; package Entity;
public interface HasPosition { public interface Positionable {
Position getPosition(); Position getPosition();
void setPosition(Position position); void setPosition(Position position);
} }

View File

@@ -1,7 +0,0 @@
package Inventory;
import java.util.List;
public interface HasInventory {
Inventory getInventory();
}

View File

@@ -1,6 +1,5 @@
package Inventory; package Inventory;
import Item.Item;
import Item.ItemStack; import Item.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
@@ -27,12 +26,11 @@ public class Inventory {
public void addItem(ItemStack stack) { public void addItem(ItemStack stack) {
if (stack.getWeight() + getCurrentWeight() > maxWeight) { if (stack.getWeight() + getCurrentWeight() > maxWeight) {
if(stack.isSingleItem()) return;
trySubstack(stack); trySubstack(stack);
return; } else {
}
items.add(stack); items.add(stack);
} }
}
private void trySubstack(ItemStack stack) { private void trySubstack(ItemStack stack) {
int stackSize = getMaxStackSize(stack); int stackSize = getMaxStackSize(stack);
@@ -49,26 +47,9 @@ public class Inventory {
public int getCurrentWeight() { public int getCurrentWeight() {
int currentWeight = 0; int currentWeight = 0;
for (ItemStack item : items) { for (ItemStack stack : items) {
currentWeight += item.getItem().getWeight(); currentWeight += stack.getWeight();
} }
return currentWeight; return currentWeight;
} }
private int calculateStackWeight(ItemStack stack) {
return stack.getItem().getWeight() * stack.getQuantity();
}
public boolean containsItem(Item item) {
for (ItemStack stack : items) {
if (stack.item().equals(item)) {
return true;
}
}
return false;
}
public int getMaxWeight() {
return maxWeight;
}
} }

View File

@@ -0,0 +1,5 @@
package Inventory;
public interface InventoryHolder {
Inventory getInventory();
}

View File

@@ -1,7 +1,5 @@
package Item; package Item;
import Inventory.Inventory;
public record ItemStack(Item item, int quantity) { public record ItemStack(Item item, int quantity) {
public ItemStack { public ItemStack {
if (quantity <= 0) { if (quantity <= 0) {
@@ -16,10 +14,6 @@ public record ItemStack(Item item, int quantity) {
return quantity; return quantity;
} }
public boolean isSingleItem() {
return quantity == 1;
}
public int getWeight() { public int getWeight() {
return item.getWeight() * quantity; return item.getWeight() * quantity;
} }

View File

@@ -3,8 +3,6 @@ package Job;
import Shared.ExperienceTable; import Shared.ExperienceTable;
import Shared.Levelable; import Shared.Levelable;
import java.util.Objects;
public abstract class Job implements Levelable { public abstract class Job implements Levelable {
protected int level; protected int level;
protected int experience; protected int experience;
@@ -43,21 +41,4 @@ public abstract class Job implements Levelable {
level++; level++;
} }
@Override
public String toString() {
return String.format("Job: %s. Level: %d", name, level);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
return o != null && getClass() == o.getClass();
}
@Override
public int hashCode() {
return Objects.hash(name);
}
} }

View File

@@ -1,6 +1,6 @@
package Job; package Job;
public interface HasJob { public interface JobHolder {
Job getJob(); Job getJob();
void learnJob(Job job); void learnJob(Job job);
} }

View File

@@ -1,19 +1,19 @@
package Job; package Job;
import Inventory.HasInventory; import Inventory.InventoryHolder;
import Item.ItemStack; import Item.ItemStack;
import Terrain.Biome; import Terrain.Biome;
public class Miner extends Job { public class Miner extends Job {
HasInventory actor; InventoryHolder actor;
public Miner(HasInventory actor) { public Miner(InventoryHolder actor) {
super("Miner"); super("Miner");
this.actor = actor; this.actor = actor;
} }
public HasInventory getActor() { public InventoryHolder getActor() {
return actor; return actor;
} }

View File

@@ -41,6 +41,9 @@ public class LootTable<T> {
return entry.item(); return entry.item();
} }
} }
// Unreachable code. entries always have an entry or the class cant be instantiated.
// Cant put system into this state.
// only have a return here due to compiler requiring it.
return null; return null;
} }

View File

@@ -0,0 +1,14 @@
import Terrain.Biome;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class BiomeTest {
@Test
void instantiates_with_name() {
var biome = Biome.COAST;
assertEquals("Coast", biome.getName());
}
}

View File

@@ -0,0 +1,38 @@
import Action.DigAction;
import Entity.Player;
import Job.Miner;
import Terrain.Biome;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
public class DigActionTest {
@Test
void can_be_executed_as_miner() {
var mockMiner = mock(Miner.class);
var player = mock(Player.class);
when(player.getJob()).thenReturn(mockMiner);
var biome = mock(Biome.class);
var action = new DigAction(biome);
action.execute(player);
verify(mockMiner, times(1)).dig(biome);
}
@Test
void digging_when_not_miner_throws_error() {
var player = mock(Player.class);
when(player.getJob()).thenReturn(null);
var biome = mock(Biome.class);
var action = new DigAction(biome);
assertThrows(IllegalStateException.class, () -> action.execute(player));
}
@Test
void digging_when_not_have_job_throws_error() {
var player = mock(Player.class);
var biome = mock(Biome.class);
var action = new DigAction(biome);
assertThrows(IllegalStateException.class, () -> action.execute(player));
}
}

View File

@@ -40,11 +40,12 @@ public class InventoryTest {
var item = new BasicItem("iron_sword", "Iron Sword", 10); var item = new BasicItem("iron_sword", "Iron Sword", 10);
var stack = new ItemStack(item, 1); var stack = new ItemStack(item, 1);
inventory.addItem(stack); inventory.addItem(stack);
assertThat(inventory.getItems().size(), is(0)); assertThat(inventory.getItems().size(), is(0));
} }
@Test @Test
void stack_can_be_added_up_to_capacity() { void add_substack_if_item_fits() {
var inventory = new Inventory(5); var inventory = new Inventory(5);
var item = new BasicItem("sand_grain", "Sand Grain", 1); var item = new BasicItem("sand_grain", "Sand Grain", 1);
var stack = new ItemStack(item, 8); var stack = new ItemStack(item, 8);
@@ -57,7 +58,21 @@ public class InventoryTest {
hasProperty("quantity", equalTo(5))) hasProperty("quantity", equalTo(5)))
)); ));
} }
@Test
void current_weight_is_zero_if_no_item_is_added() {
var inventory = new Inventory(5);
assertThat(inventory.getCurrentWeight(), is(0));
}
@Test
void current_weight_calculates_correctly() {
var inventory = new Inventory(10);
var item = new BasicItem("iron_sword", "Iron Sword", 5);
var item2 = new BasicItem("berry", "Berry", 1);
inventory.addItem(new ItemStack(item, 1));
inventory.addItem(new ItemStack(item2, 2));
assertThat(inventory.getCurrentWeight(), is(7));
}
} }

View File

@@ -0,0 +1,29 @@
import Item.BasicItem;
import Item.ItemStack;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ItemStackTest {
@Test
void instantiated_with_no_quantity_throws_exception() {
assertThrows(IllegalArgumentException.class, () -> new ItemStack(
new BasicItem("id", "name", 5), 0
));
}
@Test
void instantiated_with_negative_quantity_throws_exception() {
assertThrows(IllegalArgumentException.class, () -> new ItemStack(
new BasicItem("id", "name", 5), -4
));
}
@Test
void can_be_created_with_positive_quantity() {
var i = new ItemStack(new BasicItem("id", "name", 5), 5);
assertThat(i, instanceOf(ItemStack.class));
}
}

View File

@@ -0,0 +1,27 @@
import Item.BasicItem;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ItemTest {
private BasicItem item() {
return new BasicItem("item_id", "item", 5);
}
@Test
void instantiates_with_id() {
var i = item();
assertEquals("item_id", i.getId());
}
@Test
void instantiate_with_name() {
var item = item();
assertEquals("item", item.getName());
}
@Test
void instantiates_with_weight() {
var i = item();
assertEquals(5, i.getWeight());
}
}

View File

@@ -42,5 +42,4 @@ public class LootTableTest {
assertThat(result, equalTo("Iron")); assertThat(result, equalTo("Iron"));
} }
} }

View File

@@ -1,4 +1,6 @@
import Action.DigAction;
import Entity.Player; import Entity.Player;
import Inventory.Inventory;
import Job.Miner; import Job.Miner;
import Shared.RandomProvider; import Shared.RandomProvider;
import Terrain.Biome; import Terrain.Biome;
@@ -7,9 +9,9 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
public class MinerTest { public class MinerTest {
private Player defaultPlayer() {return new Player("John"); } private Player defaultPlayer() {return new Player("John"); }
@@ -21,6 +23,12 @@ public class MinerTest {
assertEquals(2, job.getLevel()); assertEquals(2, job.getLevel());
} }
@Test
void can_be_created_with_player() {
var miner = new Miner(defaultPlayer());
assertThat(miner.getActor(), equalTo(defaultPlayer()));
}
@Test @Test
void can_gain_xp() { void can_gain_xp() {
var job = new Miner(defaultPlayer()); var job = new Miner(defaultPlayer());
@@ -30,7 +38,7 @@ public class MinerTest {
@Test @Test
void level_up_when_experience_cap_is_reached() { void level_up_when_experience_cap_is_reached() {
var job = new Miner(defaultPlayer()); Miner job = new Miner(defaultPlayer());
job.gainExperience(job.remainingXpUntilLevelUp()); job.gainExperience(job.remainingXpUntilLevelUp());
assertEquals(2, job.getLevel()); assertEquals(2, job.getLevel());
} }
@@ -65,6 +73,15 @@ public class MinerTest {
) )
); );
} }
@Test
void dig_use_workers_inventory() {
var mockInventory = mock(Inventory.class);
var miner = new Miner(new Player("John", mockInventory));
miner.dig(Biome.MOUNTAIN);
verify(mockInventory).addItem(any());
}
} }

View File

@@ -2,14 +2,13 @@ import Action.DigAction;
import Action.LearnSpellAction; import Action.LearnSpellAction;
import Combat.OffensiveDamageSpell; import Combat.OffensiveDamageSpell;
import Entity.Position; import Entity.Position;
import Inventory.Inventory;
import Job.Miner; import Job.Miner;
import Entity.Player; import Entity.Player;
import Terrain.Biome;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import Job.Wizard; import Job.Wizard;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@@ -19,6 +18,15 @@ class PlayerTest {
return new Player("abc"); return new Player("abc");
} }
@Test
void player_can_be_created_with_job_and_inventory() {
var job = mock(Miner.class);
var inventory = mock(Inventory.class);
var player = new Player("abc", job, inventory);
assertThat(player, instanceOf(Player.class));
}
@Test @Test
public void is_dead_if_health_is_zero() { public void is_dead_if_health_is_zero() {
var p = defaultPlayer(); var p = defaultPlayer();
@@ -26,6 +34,13 @@ class PlayerTest {
assertFalse(p.isAlive()); assertFalse(p.isAlive());
} }
@Test
public void is_alive_if_has_health() {
var p = defaultPlayer();
p.setHealth(10);
assertTrue(p.isAlive());
}
@Test @Test
void get_health_returns_health() { void get_health_returns_health() {
var p = defaultPlayer(); var p = defaultPlayer();
@@ -62,6 +77,37 @@ class PlayerTest {
assertEquals(new Position(1,1), p.getPosition()); assertEquals(new Position(1,1), p.getPosition());
} }
@Test
public void can_not_walk_two_spaces_y() {
var p = defaultPlayer();
p.moveTo(new Position(1,2));
assertEquals(new Position(0,0), p.getPosition());
}
@Test
public void can_not_walk_two_spaces_x() {
var p = defaultPlayer();
p.moveTo(new Position(2,1));
assertEquals(new Position(0,0), p.getPosition());
}
@Test
void can_not_walk_two_spaces_y_negative() {
var p = defaultPlayer();
p.setPosition(new Position(3,3));
p.moveTo(new Position(1,3));
assertEquals(new Position(3,3), p.getPosition());
}
@Test
void can_not_walk_two_spaces_x_negative() {
var p = defaultPlayer();
p.setPosition(new Position(3,3));
p.moveTo(new Position(3,1));
assertEquals(new Position(3,3), p.getPosition());
}
@Test @Test
public void can_change_job() { public void can_change_job() {
var p = defaultPlayer(); var p = defaultPlayer();
@@ -81,6 +127,17 @@ class PlayerTest {
verify(mockAction, times(1)).execute(p); verify(mockAction, times(1)).execute(p);
} }
@Test
void miner_can_dig_multiple_times() {
var p = new Player("John");
p.learnJob(new Miner(p));
var mockAction = mock(DigAction.class);
for(int i = 0; i < 10; i++) {
p.performAction(mockAction);
}
verify(mockAction, times(10)).execute(p);
}
@Test @Test
void wizard_can_learn_spell() { void wizard_can_learn_spell() {
var p = new Player("Bob"); var p = new Player("Bob");