flow: tests

This commit is contained in:
cha0s 2021-01-03 18:02:05 -06:00
parent d0ca3ff0e2
commit 82ae1df5fc
31 changed files with 251 additions and 126 deletions

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -21,7 +21,7 @@ describe('@avocado/core', () => {
},
})(class {}) {};
const object = new Class();
expect(hasInitialized).to.equal(true);
expect(hasInitialized).to.be.true;
});
it('accepts defaults', () => {
class Class extends Property('property', {
@ -59,9 +59,9 @@ describe('@avocado/core', () => {
emit(type, o, v) {emitted = ('propertyChanged' === type && 420 === v)}
};
const object = new Class();
expect(emitted).to.equal(false);
expect(emitted).to.be.false;
object.property = 420;
expect(emitted).to.equal(true);
expect(emitted).to.be.true;
});
it('accepts emitter', () => {
let emitted = false;
@ -72,9 +72,9 @@ describe('@avocado/core', () => {
track: true,
})(class {}) {};
const object = new Class();
expect(emitted).to.equal(false);
expect(emitted).to.be.false;
object.property = 420;
expect(emitted).to.equal(true);
expect(emitted).to.be.true;
});
it('accepts comparator', () => {
let emitted = false;
@ -88,11 +88,11 @@ describe('@avocado/core', () => {
track: true,
})(class {}) {};
const object = new Class();
expect(emitted).to.equal(false);
expect(emitted).to.be.false;
object.property = [0, 0];
expect(emitted).to.equal(false);
expect(emitted).to.be.false;
object.property = [1, 0];
expect(emitted).to.equal(true);
expect(emitted).to.be.true;
});
});
});

View File

@ -68,7 +68,6 @@ export default (latus) => class EntityList extends decorate(JsonResource) {
if ('client' !== SIDE) {
this._informedEntities.set(entity, []);
}
entity.hydrate();
entity.attachToList(this);
entity.once('destroy', () => {
this.removeEntity(entity);

View File

@ -4,25 +4,18 @@ import {Packet} from '@latus/socket';
export default class TraitUpdatePositionedPositionPacket extends Packet {
static pack(packet) {
const data = packet.data[1];
data.position = Vector.packToUint32(data.position);
// eslint-disable-next-line no-param-reassign
packet.data[1] = Vector.packToUint32(packet.data[1]);
return super.pack(packet);
}
static get schema() {
return {
...super.schema,
data: {
position: 'uint32',
},
};
static get data() {
return 'uint32';
}
static unpack(packet) {
const unpacked = super.unpack(packet);
const {data} = unpacked;
data.position = Vector.unpackFromUint32(data.position);
return unpacked;
return Vector.unpackFromUint32(unpacked);
}
}

View File

@ -82,7 +82,12 @@ export default class Mobile extends decorate(Trait) {
methods() {
return {
moveFor: (vector, duration) => new TickingPromise(
moveFor: (vector, duration) => {
if (duration <= 0) {
return undefined;
}
this.entity.requestMovement(Vector.normalize(vector));
return new TickingPromise(
() => {},
(elapsed, resolve) => {
// eslint-disable-next-line no-param-reassign
@ -93,7 +98,8 @@ export default class Mobile extends decorate(Trait) {
}
this.entity.requestMovement(Vector.normalize(vector));
},
),
);
},
applyMovement: (vector) => {
this.appliedMovement = Vector.add(this.appliedMovement, vector);

View File

@ -19,6 +19,26 @@ const decorate = compose(
// < 16768 will pack into 1 short per axe and give +/- 0.25 precision.
export default class Positioned extends decorate(Trait) {
constructor(...args) {
super(...args);
this.on('_positionChanged', this.on_positionChanged, this);
const {x, y} = this.state;
this._position = [x, y];
this.entity.position[0] = x;
this.entity.position[1] = y;
if ('client' === SIDE) {
this.serverPosition = this._position;
this.serverPositionDirty = false;
this.on('serverPositionChanged', this.onServerPositionChanged, this);
}
}
acceptPacket(packet) {
if ('TraitUpdatePositionedPosition' === packet.constructor.type) {
[this.serverX, this.serverY] = packet.data;
}
}
static behaviorTypes() {
return {
position: {
@ -57,20 +77,6 @@ export default class Positioned extends decorate(Trait) {
};
}
constructor(...args) {
super(...args);
this.on('_positionChanged', this.on_positionChanged, this);
const {x, y} = this.state;
this._position = [x, y];
this.entity.position[0] = x;
this.entity.position[1] = y;
if ('client' === SIDE) {
this.serverPosition = this._position;
this.serverPositionDirty = false;
this.on('serverPositionChanged', this.onServerPositionChanged, this);
}
}
destroy() {
this.off('_positionChanged', this.on_positionChanged);
if ('client' === SIDE) {
@ -78,12 +84,6 @@ export default class Positioned extends decorate(Trait) {
}
}
acceptPacket(packet) {
if ('TraitUpdatePositionedPosition' === packet.constructor.type) {
[this.serverX, this.serverY] = packet.data.position;
}
}
// eslint-disable-next-line camelcase
on_positionChanged(oldPosition, newPosition) {
[this.entity.position[0], this.entity.position[1]] = newPosition;
@ -102,10 +102,8 @@ export default class Positioned extends decorate(Trait) {
const {x, y} = this.stateDifferences();
if (x || y) {
return [
'TraitUpdatePositionedPositionPacket',
{
position: this.entity.position,
},
'TraitUpdatePositionedPosition',
this.entity.position,
];
}
return undefined;

View File

@ -140,15 +140,15 @@ export default (latus) => class Spawner extends decorate(Trait) {
if (!json.traits) {
json.traits = {};
}
if (!json.traits.positioned) {
json.traits.positioned = {};
if (!json.traits.Positioned) {
json.traits.Positioned = {};
}
if (!json.traits.positioned.state) {
json.traits.positioned.state = {};
if (!json.traits.Positioned.state) {
json.traits.Positioned.state = {};
}
[
json.traits.positioned.state.x,
json.traits.positioned.state.y,
json.traits.Positioned.state.x,
json.traits.Positioned.state.y,
] = position;
/* eslint-enable no-param-reassign */
return json;
@ -156,14 +156,14 @@ export default (latus) => class Spawner extends decorate(Trait) {
destinationEntityList() {
if (
this.entity.is('listed')
this.entity.is('Listed')
&& this.entity.list
) {
return this.entity.list;
}
if (
this.entity.wielder
&& this.entity.wielder.is('listed')
&& this.entity.wielder.is('Listed')
&& this.entity.wielder.list
) {
return this.entity.wielder.list;
@ -220,7 +220,13 @@ export default (latus) => class Spawner extends decorate(Trait) {
if (!spawnJSON) {
return undefined;
}
return this.entity.spawnRaw(merge(spawnJSON, json));
return this.entity.spawnRaw(merge(
spawnJSON,
json,
{
arrayMerge: (l, r) => r,
},
));
},
spawnAt: (key, position, json = {}) => (
@ -238,7 +244,7 @@ export default (latus) => class Spawner extends decorate(Trait) {
this.children.push(null);
const list = this.destinationEntityList();
const {fromResourceType: {Entity}} = resource(latus);
const child = await Entity.loadOrInstance(json);
const child = await Entity.load(json);
this.children[childIndex] = child;
// Listen for destroy event.
const listener = this.removeChild.bind(this, child);
@ -249,7 +255,7 @@ export default (latus) => class Spawner extends decorate(Trait) {
return child;
},
spawnRawAt: (position, json = {}) => (
spawnRawAt: (json = {}, position) => (
this.maySpawn()
? this.entity.spawnRaw(this.augmentJSONWithPosition(json, position))
: undefined

View File

@ -35,15 +35,15 @@ describe(name, () => {
});
});
it('exists', async () => {
expect(entity.is('Alive')).to.equal(true);
expect(entity.is('Alive')).to.be.true;
});
it('is alive', async () => {
expect(entity.isDying).to.equal(false);
expect(entity.isDying).to.be.false;
});
it('can die', async () => {
entity.life = 0;
entity.tick(0);
expect(entity.isDying).to.equal(true);
expect(entity.isDying).to.be.true;
});
it('clamps life', async () => {
entity.life = 120;
@ -65,10 +65,10 @@ describe(name, () => {
},
});
entity.tick(0);
expect(entity.isDying).to.equal(false);
expect(entity.isDying).to.be.false;
entity.life = 10;
entity.tick(0);
expect(entity.isDying).to.equal(true);
expect(entity.isDying).to.be.true;
});
it('runs actions on death', async () => {
let didActions;
@ -94,7 +94,7 @@ describe(name, () => {
}, 16.66);
await entity.forceDeath();
clearInterval(handle);
expect(didActions).to.equal(true);
expect(didActions).to.be.true;
});
describe('Packets', () => {
let entity2;
@ -124,7 +124,7 @@ describe(name, () => {
expect(packets[0].constructor.type).to.equal('TraitUpdateAlive');
expect(packets[0].data).to.deep.equal({life: 0, maxLife: 100});
expect(packets[1].constructor.type).to.equal('Died');
expect(entity2.isDying).to.equal(false);
expect(entity2.isDying).to.be.false;
const promise = new Promise((resolve) => {
entity2.on('isDyingChanged', resolve);
});

View File

@ -33,7 +33,7 @@ describe(name, () => {
});
});
it('exists', async () => {
expect(entity.is('Directional')).to.equal(true);
expect(entity.is('Directional')).to.be.true;
});
it('tracks movement', async () => {
entity.emit('movementRequest', [1, 0]);

View File

@ -34,9 +34,9 @@ describe(name, () => {
traits(latus).fromType['TestTrait'] = TestTrait;
const trait = await TestTrait.load();
entity.addTrait([TestTrait, {}]);
expect(entity.is('TestTrait')).to.equal(true);
expect(entity.is('TestTrait')).to.be.true;
entity.removeTrait('TestTrait');
expect(entity.is('TestTrait')).to.equal(false);
expect(entity.is('TestTrait')).to.be.false;
});
it('can add traits asynchronously', async () => {
const DELAY = 30;

View File

@ -27,7 +27,7 @@ describe(name, () => {
});
});
it('exists', async () => {
expect(entity.is('Existent')).to.equal(true);
expect(entity.is('Existent')).to.be.true;
});
it('can transition', async () => {
entity.foobar = 10;
@ -43,7 +43,7 @@ describe(name, () => {
return tickingPromise;
});
it('can be destroyed', async () => {
expect(entity.isTicking).to.equal(true);
expect(entity.isTicking).to.be.true;
const promise = Promise.all([
new Promise((resolve) => {
entity.on('destroy', resolve);

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -28,7 +28,7 @@ describe(name, () => {
});
});
it('exists', async () => {
expect(entity.is('Listed')).to.equal(true);
expect(entity.is('Listed')).to.be.true;
});
it('can be added to list quadtree', async () => {
entity.isVisible = true;

View File

@ -24,19 +24,51 @@ describe(name, () => {
entity = await Entity.load({
traits: {
Mobile: {},
Positioned: {},
},
});
});
it('exists', async () => {
expect(entity.is('Mobile')).to.equal(true);
expect(entity.is('Mobile')).to.be.true;
});
it('can request movement', async () => {
entity.speed = 100;
entity.requestMovement([1, 0]);
entity.tick(1);
expect(entity.position).to.deep.equal([100, 0]);
entity.tick(1);
expect(entity.position).to.deep.equal([100, 0]);
entity.isMobile = false;
entity.requestMovement([1, 0]);
entity.tick(1);
expect(entity.position).to.deep.equal([100, 0]);
});
it('can apply movement', async () => {
const trait = entity.traitInstance('Mobile');
entity.applyMovement([10, 0]);
expect(trait.appliedMovement).to.deep.equal([10, 0]);
entity.applyMovement([10, 0]);
expect(trait.appliedMovement).to.deep.equal([20, 0]);
entity.tick(0);
expect(trait.appliedMovement).to.deep.equal([0, 0]);
});
it('can force movement', async () => {
expect(entity.speed).to.equal(0);
entity.forceMovement([10, 0]);
expect(entity.position).to.deep.equal([10, 0]);
});
it('can move for a time', async () => {
entity.speed = 10;
const tickingPromise = entity.moveFor([1, 0], 1);
entity.addTickingPromise(tickingPromise);
expect(entity.position).to.deep.equal([0, 0]);
entity.tick(0.25);
expect(entity.position).to.deep.equal([2.5, 0]);
entity.tick(0.25);
expect(entity.position).to.deep.equal([5, 0]);
entity.tick(0.5);
expect(entity.position).to.deep.equal([10, 0]);
return tickingPromise;
});
});
});

View File

@ -23,14 +23,29 @@ describe(name, () => {
beforeEach(async () => {
entity = await Entity.load({
traits: {
Perishable: {},
Existent: {},
Perishable: {
params: {
ttl: 10,
},
},
},
});
});
it('exists', async () => {
expect(entity.is('Perishable')).to.equal(true);
expect(entity.is('Perishable')).to.be.true;
});
it('expires', async () => {
const promise = Promise.all([
new Promise((resolve) => {
entity.on('destroy', resolve);
}),
new Promise((resolve) => {
entity.on('destroyed', resolve);
}),
]);
entity.tick(10);
return promise;
});
});
});

View File

@ -1,4 +1,5 @@
import {resource} from '@avocado/resource';
import {normalize} from '@avocado/s13n';
import {Latus} from '@latus/core';
import {expect} from 'chai';
@ -13,6 +14,7 @@ describe(name, () => {
['@avocado/entity', `${__dirname}/../src`],
'@avocado/resource',
'@avocado/traits',
'@latus/socket',
]);
await Promise.all(latus.invokeFlat('@latus/core/starting'));
({fromResourceType: {Entity, EntityList}} = resource(latus));
@ -28,9 +30,23 @@ describe(name, () => {
});
});
it('exists', async () => {
expect(entity.is('Positioned')).to.equal(true);
expect(entity.is('Positioned')).to.be.true;
});
it('generates and accepts movement packets', async () => {
entity.setPosition([1, 1]);
const packets = normalize(latus, entity.traitInstance('Positioned').packets());
expect(packets).to.have.lengthOf(1);
expect(packets[0].constructor.type).to.equal('TraitUpdatePositionedPosition');
expect(packets[0].data).to.deep.equal([1, 1]);
const entity2 = await Entity.load({
traits: {
Positioned: {},
},
});
expect(entity2.position).to.deep.equal([0, 0]);
const trait = entity2.traitInstance('Positioned');
trait.acceptPacket(packets[0]);
expect(trait.serverPosition).to.deep.equal([1, 1]);
});
});
});

View File

@ -20,21 +20,81 @@ describe(name, () => {
describe('Traits', () => {
describe('Spawner', () => {
let entity;
let list;
beforeEach(async () => {
entity = await Entity.load({
traits: {
Spawner: {},
Listed: {},
Spawner: {
params: {
spawns: {
testy: {
traits: {
Alive: {},
Listed: {},
Positioned: {},
},
},
},
},
},
},
});
list = new EntityList();
list.addEntity(entity);
});
it('exists', async () => {
expect(entity.is('Spawner')).to.equal(true);
expect(entity.is('Spawner')).to.be.true;
});
it('can spawn from list', async () => {
it('can spawn from key', async () => {
const spawned = await entity.spawn('testy');
expect(spawned.is('Alive')).to.be.true;
const spawned2 = await entity.spawn('testy', {
traits: {
Alive: {
state: {
life: 50,
},
},
},
});
expect(spawned2.life).to.equal(50);
const spawned3 = await entity.spawnAt('testy', [69, 420]);
expect(spawned3.position).to.deep.equal([69, 420]);
});
it('can spawn from arbitrary JSON', async () => {
const spawned = await entity.spawnRaw({
traits: {
Listed: {},
Mobile: {},
},
});
expect(spawned.is('Mobile')).to.be.true;
const spawned2 = await entity.spawnRawAt(
{
traits: {
Listed: {},
Mobile: {},
},
},
[311, 200],
);
expect(spawned2.position).to.deep.equal([311, 200]);
});
it('can kill all children', async () => {
const COUNT = 15;
for (let i = 0; i < COUNT; ++i) {
await entity.spawnRaw({
traits: {
Existent: {},
Listed: {},
Mobile: {},
},
});
}
expect(Object.keys(list._entities)).to.have.lengthOf(COUNT + 1);
entity.killAllChildren();
expect(Object.keys(list._entities)).to.have.lengthOf(1);
});
});
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -5,17 +5,17 @@ import * as Rectangle from '../src/rectangle'
describe('@avocado/math', () => {
describe('Rectangle', function() {
it('can calculate intersections', function() {
expect(Rectangle.intersects([0, 0, 16, 16], [8, 8, 24, 24])).to.equal(true);
expect(Rectangle.intersects([0, 0, 16, 16], [16, 16, 32, 32])).to.equal(false);
expect(Rectangle.isTouching([0, 0, 16, 16], [0, 0])).to.equal(true);
expect(Rectangle.isTouching([0, 0, 16, 16], [16, 16])).to.equal(false);
expect(Rectangle.intersects([0, 0, 16, 16], [8, 8, 24, 24])).to.be.true;
expect(Rectangle.intersects([0, 0, 16, 16], [16, 16, 32, 32])).to.be.false;
expect(Rectangle.isTouching([0, 0, 16, 16], [0, 0])).to.be.true;
expect(Rectangle.isTouching([0, 0, 16, 16], [16, 16])).to.be.false;
expect(Rectangle.intersection([0, 0, 16, 16], [8, 8, 24, 24])).to.deep.equal([8, 8, 8, 8]);
expect(Rectangle.united([0, 0, 4, 4], [4, 4, 8, 8])).to.deep.equal([0, 0, 12, 12]);
});
it('can compose and decompose', function() {
var rectangle;
rectangle = Rectangle.compose([0, 0], [16, 16]);
expect(Rectangle.equals(rectangle, [0, 0, 16, 16])).to.equal(true);
expect(Rectangle.equals(rectangle, [0, 0, 16, 16])).to.be.true;
expect(Rectangle.position(rectangle)).to.deep.equal([0, 0]);
expect(Rectangle.size(rectangle)).to.deep.equal([16, 16]);
});
@ -23,9 +23,9 @@ describe('@avocado/math', () => {
var rectangle, rectangle2;
rectangle = [0, 0, 16, 16];
rectangle2 = Rectangle.copy(rectangle);
expect(Rectangle.equals(rectangle, rectangle2)).to.equal(true);
expect(Rectangle.equals(rectangle, rectangle2)).to.be.true;
rectangle[0] = 6;
expect(Rectangle.equals(rectangle, rectangle2)).to.equal(false);
expect(Rectangle.equals(rectangle, rectangle2)).to.be.false;
});
it('can convert to an object', function() {
var rectangle;
@ -47,14 +47,14 @@ describe('@avocado/math', () => {
expect(Rectangle.translated([0, 0, 16, 16], [8, 8])).to.deep.equal([8, 8, 16, 16]);
});
it('can check for null', function() {
expect(Rectangle.isNull(null)).to.equal(true);
expect(Rectangle.isNull(3)).to.equal(true);
expect(Rectangle.isNull([1])).to.equal(true);
expect(Rectangle.isNull([1, 1])).to.equal(true);
expect(Rectangle.isNull([1, 1, 1])).to.equal(true);
expect(Rectangle.isNull([1, 1, 1, 1, 1])).to.equal(true);
expect(Rectangle.isNull([0, 0, 1, 1])).to.equal(false);
expect(Rectangle.isNull([0, 0, 1, 0])).to.equal(true);
expect(Rectangle.isNull(null)).to.be.true;
expect(Rectangle.isNull(3)).to.be.true;
expect(Rectangle.isNull([1])).to.be.true;
expect(Rectangle.isNull([1, 1])).to.be.true;
expect(Rectangle.isNull([1, 1, 1])).to.be.true;
expect(Rectangle.isNull([1, 1, 1, 1, 1])).to.be.true;
expect(Rectangle.isNull([0, 0, 1, 1])).to.be.false;
expect(Rectangle.isNull([0, 0, 1, 0])).to.be.true;
});
it('can round', function() {
expect(Rectangle.round([3.14, 4.70, 5.32, 1.8])).to.deep.equal([3, 5, 5, 2]);

View File

@ -56,20 +56,20 @@ describe('@avocado/math', () => {
it('can deep copy', () => {
const vector = [0, 0];
const vector2 = Vector.copy(vector);
expect(Vector.equals(vector, vector2)).to.equal(true);
expect(Vector.equals(vector, vector2)).to.be.true;
vector[0] = 1;
expect(Vector.equals(vector, vector2)).to.equal(false);
expect(Vector.equals(vector, vector2)).to.be.false;
});
it('can test for 0', () => {
expect(Vector.isZero([0, 0])).to.equal(true);
expect(Vector.isZero([1, 0])).to.equal(false);
expect(Vector.isZero([0, 0])).to.be.true;
expect(Vector.isZero([1, 0])).to.be.false;
});
it('can test for NULL', () => {
expect(Vector.isNull([0, 1])).to.equal(true);
expect(Vector.isNull([1, 1])).to.equal(false);
expect(Vector.isNull(null)).to.equal(true);
expect(Vector.isNull([1])).to.equal(true);
expect(Vector.isNull([1, 1, 1])).to.equal(true);
expect(Vector.isNull([0, 1])).to.be.true;
expect(Vector.isNull([1, 1])).to.be.false;
expect(Vector.isNull(null)).to.be.true;
expect(Vector.isNull([1])).to.be.true;
expect(Vector.isNull([1, 1, 1])).to.be.true;
});
it('can calculate angle', () => {
expect(Vector.toRadians([1, 0])).to.be.closeTo(0, 0.0001);

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});

View File

@ -4,6 +4,6 @@ const {name} = require('../package.json');
describe(name, () => {
it('exists', () => {
expect(true).to.equal(true);
expect(true).to.be.true;
})
});