/*
* The MIT License (MIT)
*
* FXGL - JavaFX Game Library
*
* Copyright (c) 2015-2017 AlmasB (almaslvl@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.almasb.fxgl.ecs;
import com.almasb.fxgl.ecs.component.BooleanComponent;
import com.almasb.fxgl.ecs.component.DoubleComponent;
import com.almasb.fxgl.ecs.component.Required;
import com.almasb.fxgl.ecs.serialization.SerializableComponent;
import com.almasb.fxgl.ecs.serialization.SerializableControl;
import com.almasb.fxgl.io.serialization.Bundle;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.Optional;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
/**
* @author Almas Baimagambetov (AlmasB) (almaslvl@gmail.com)
*/
public class EntityTest {
private Entity entity;
@Before
public void setUp() {
entity = new Entity();
}
@Test
public void testControls() {
TestControl control = new TestControl();
entity.addControl(control);
Optional<TestControl> maybe = entity.getControl(TestControl.class);
assertTrue(maybe.isPresent());
assertEquals(control, maybe.get());
entity.removeControl(TestControl.class);
assertFalse(entity.getControl(TestControl.class).isPresent());
entity.addControl(control);
maybe = entity.getControl(TestControl.class);
assertTrue(maybe.isPresent());
assertEquals(control, maybe.get());
entity.removeAllControls();
assertFalse(entity.getControl(TestControl.class).isPresent());
}
@Test
public void testGetControl() {
TestControl control = new TestControl();
entity.addControl(control);
assertEquals(control, entity.getControl(TestControl.class).get());
assertEquals(control, entity.getControlUnsafe(TestControl.class));
}
@Test(expected = IllegalArgumentException.class)
public void testControlsAnonymous() {
entity.addControl(new Control() {
@Override
public void onAdded(Entity entity) {}
@Override
public void onUpdate(Entity entity, double tpf) {}
@Override
public void onRemoved(Entity entity) {}
@Override
public boolean isPaused() {
return false;
}
@Override
public void pause() {
}
@Override
public void resume() {
}
});
}
@Test(expected = IllegalArgumentException.class)
public void testControlsDuplicate() {
entity.addControl(new TestControl());
entity.addControl(new TestControl());
}
@Test
public void testComponents() {
HPComponent hp = new HPComponent(100);
entity.addComponent(hp);
Optional<HPComponent> maybe = entity.getComponent(HPComponent.class);
assertTrue(maybe.isPresent());
assertEquals(hp, maybe.get());
entity.removeComponent(HPComponent.class);
assertFalse(entity.getComponent(HPComponent.class).isPresent());
entity.addComponent(hp);
maybe = entity.getComponent(HPComponent.class);
assertTrue(maybe.isPresent());
assertEquals(hp, maybe.get());
entity.removeAllComponents();
assertFalse(entity.getComponent(HPComponent.class).isPresent());
}
@Test
public void testGetComponent() {
TestComponent component = new TestComponent();
entity.addComponent(component);
assertEquals(component, entity.getComponent(TestComponent.class).get());
assertEquals(component, entity.getComponentUnsafe(TestComponent.class));
}
@Test(expected = IllegalStateException.class)
public void testRequiredAllMissing() {
entity.addComponent(new ArmorComponent());
}
@Test(expected = IllegalStateException.class)
public void testRequiredOneMissing() {
entity.addComponent(new TestComponent());
entity.addComponent(new ArmorComponent());
}
@Test
public void testRequired() {
entity.addComponent(new TestComponent());
entity.addComponent(new HPComponent(33));
entity.addComponent(new ArmorComponent());
assertTrue(true);
}
@Test(expected = IllegalArgumentException.class)
public void testRequiredRemovedComponent() {
entity.addComponent(new TestComponent());
entity.addComponent(new HPComponent(33));
entity.addComponent(new ArmorComponent());
entity.removeComponent(HPComponent.class);
}
@Test(expected = IllegalArgumentException.class)
public void testRequiredRemovedControl() {
entity.addComponent(new HPComponent(33));
entity.addControl(new HPControl());
entity.removeComponent(HPComponent.class);
}
@Test(expected = IllegalArgumentException.class)
public void testComponentsAnonymous() {
entity.addComponent(new Component() {
@Override
public void onAdded(Entity entity) {}
@Override
public void onRemoved(Entity entity) {}
});
}
@Test(expected = IllegalArgumentException.class)
public void testComponentsDuplicate() {
HPComponent hp1 = new HPComponent(100);
HPComponent hp2 = new HPComponent(135);
entity.addComponent(hp1);
entity.addComponent(hp2);
}
@Test
public void testRemoveAllComponents() {
entity.addComponent(new TestComponent());
entity.addComponent(new HPComponent(33));
assertTrue(entity.hasComponent(TestComponent.class));
assertTrue(entity.hasComponent(HPComponent.class));
entity.removeAllComponents();
assertFalse(entity.hasComponent(TestComponent.class));
assertFalse(entity.hasComponent(HPComponent.class));
}
@Test
public void testRemoveAllControls() {
entity.addComponent(new HPComponent(33));
entity.addControl(new TestControl());
entity.addControl(new HPControl());
assertTrue(entity.hasControl(TestControl.class));
assertTrue(entity.hasControl(HPControl.class));
entity.removeAllControls();
assertFalse(entity.hasControl(TestControl.class));
assertFalse(entity.hasControl(HPControl.class));
}
@Test
public void testConcurrentModificationControl() {
entity.addControl(new ControlAddingControl());
entity.update(0.017);
}
@Test(expected = IllegalStateException.class)
public void testConcurrentModificationControl2() {
entity.addControl(new TestControl());
entity.addControl(new ControlRemovingControl());
entity.update(0.017);
}
@Test
public void testSetControlsEnabled() {
entity.addControl(new ControlAddingControl());
entity.setControlsEnabled(false);
entity.update(0.017);
}
@Test
public void testControlPause() {
Control c = new ControlAddingControl();
entity.addControl(c);
c.pause();
entity.update(0.017);
}
@Test
public void testControlResume() {
Control c = new ControlAddingControl();
entity.addControl(c);
c.pause();
c.resume();
entity.update(0.017);
}
@Test
public void testAddComponentListener() {
HPComponent hp = new HPComponent(20);
entity.addComponentListener(new ComponentListener() {
@Override
public void onComponentAdded(Component component) {
assertEquals(HPComponent.class, component.getClass());
((HPComponent)component).setValue(10);
}
@Override
public void onComponentRemoved(Component component) {
assertEquals(HPComponent.class, component.getClass());
((HPComponent)component).setValue(0);
}
});
entity.addComponent(hp);
Assert.assertEquals(10, hp.getValue(), 0);
entity.removeComponent(HPComponent.class);
Assert.assertEquals(0, hp.getValue(), 0);
}
@Test
public void testAddControlListener() {
HPControl control = new HPControl();
entity.addControlListener(new ControlListener() {
@Override
public void onControlAdded(Control control) {
assertEquals(HPControl.class, control.getClass());
((HPControl)control).value = 10;
}
@Override
public void onControlRemoved(Control control) {
assertEquals(HPControl.class, control.getClass());
((HPControl)control).value = 20;
}
});
entity.addComponent(new HPComponent(33));
entity.addControl(control);
assertEquals(10, control.value, 0);
entity.removeControl(HPControl.class);
assertEquals(20, control.value, 0);
}
@Test
public void testSave() {
entity.addComponent(new GravityComponent(true));
entity.addComponent(new CustomDataComponent("SerializationData"));
entity.addControl(new CustomDataControl("SerializableControl"));
Bundle bundle = new Bundle("Entity01234");
entity.save(bundle);
Entity entity2 = new Entity();
entity2.addComponent(new GravityComponent(false));
entity2.addComponent(new CustomDataComponent(""));
entity2.addControl(new CustomDataControl(""));
entity2.load(bundle);
assertThat(entity2.getControlUnsafe(CustomDataControl.class).data, is("SerializableControl"));
assertThat(entity2.getComponentUnsafe(CustomDataComponent.class).data, is("SerializationData"));
assertThat(entity2.getComponentUnsafe(GravityComponent.class).getValue(), is(true));
}
@Test
public void testSaveNoSuchComponent() {
Bundle bundle = new Bundle("Entity01234");
entity.save(bundle);
Entity entity2 = new Entity();
entity2.addComponent(new CustomDataComponent(""));
// even if bundle has no such component coz entity1 did not have it
// we do not fail, but log a warning
entity2.load(bundle);
}
@Test
public void testProperties() {
entity.setProperty("hp", 30);
assertThat(entity.getProperty("hp"), is(30));
entity.setProperty("hp", true);
assertThat(entity.getProperty("hp"), is(true));
}
@Test
public void testActiveCallbacks() {
HPControl hp = new HPControl();
entity.setOnActive(() -> hp.value = 30.0);
assertThat(hp.value, is(0.0));
EntityWorld world = new EntityWorld();
world.addEntity(entity);
assertThat(hp.value, is(30.0));
entity.setOnNotActive(() -> hp.value = -50.0);
assertThat(hp.value, is(30.0));
world.removeEntity(entity);
assertThat(hp.value, is(-50.0));
}
@Test(expected = IllegalArgumentException.class)
public void testNoPropertyKey() {
entity.getProperty("no_key");
}
@Test
public void testIntegrity() {
int count = 0;
EntityWorld world = new EntityWorld();
world.addEntity(entity);
world.removeEntity(entity);
try {
entity.addComponent(new HPComponent(23));
} catch (IllegalStateException e) {
count++;
}
assertThat(count, is(1));
try {
entity.removeFromWorld();
} catch (IllegalStateException e) {
count++;
}
assertThat(count, is(2));
}
private class TestControl extends AbstractControl {
@Override
public void onUpdate(Entity entity, double tpf) {}
}
private class ControlAddingControl extends AbstractControl {
@Override
public void onUpdate(Entity entity, double tpf) {
entity.addControl(new TestControl());
}
}
private class ControlRemovingControl extends AbstractControl {
@Override
public void onUpdate(Entity entity, double tpf) {
entity.removeAllControls();
}
}
@Required(HPComponent.class)
private class HPControl extends AbstractControl {
private double value = 0;
@Override
public void onUpdate(Entity entity, double tpf) {}
}
private class TestComponent extends AbstractComponent {
}
private class HPComponent extends DoubleComponent {
HPComponent(double value) {
super(value);
}
}
@Required(TestComponent.class)
@Required(HPComponent.class)
private class ArmorComponent extends AbstractComponent {
}
private class GravityComponent extends BooleanComponent {
GravityComponent(boolean value) {
super(value);
}
}
public static class CustomDataComponent extends AbstractComponent implements SerializableComponent {
public String data;
CustomDataComponent(String data) {
this.data = data;
}
@Override
public void write(Bundle bundle) {
bundle.put("data", data);
}
@Override
public void read(Bundle bundle) {
data = bundle.get("data");
}
}
public static class CustomDataControl extends AbstractControl implements SerializableControl {
public String data;
CustomDataControl(String data) {
this.data = data;
}
@Override
public void onUpdate(Entity entity, double tpf) {
}
@Override
public void write(Bundle bundle) {
bundle.put("data", data);
}
@Override
public void read(Bundle bundle) {
data = bundle.get("data");
}
}
}