Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,82 @@
'use strict';
suite('DependencyGraph', function() {
suiteSetup(function(done) {
testRequire(['modules/base/dependency_graph'], (DependencyGraph) => {
this.DependencyGraph = DependencyGraph;
done();
});
});
setup(function() {
this.graph = this.DependencyGraph();
});
suite('getAllDependent', function() {
test('a->b, b->c', function() {
this.graph.addDependency('a', 'b');
this.graph.addDependency('b', 'c');
assert.sameMembers(this.graph.getAllDependent('a'), []);
assert.sameMembers(this.graph.getAllDependent('b'), ['a']);
assert.sameMembers(this.graph.getAllDependent('c'), ['a', 'b']);
});
test('b->c, c->a', function() {
this.graph.addDependency('b', 'c');
this.graph.addDependency('a', 'b');
assert.sameMembers(this.graph.getAllDependent('a'), []);
assert.sameMembers(this.graph.getAllDependent('b'), ['a']);
assert.sameMembers(this.graph.getAllDependent('c'), ['a', 'b']);
});
test('a->b, b->c, d->b', function() {
this.graph.addDependency('a', 'b');
this.graph.addDependency('b', 'c');
this.graph.addDependency('d', 'b');
assert.sameMembers(this.graph.getAllDependent('a'), []);
assert.sameMembers(this.graph.getAllDependent('b'), ['a', 'd']);
assert.sameMembers(this.graph.getAllDependent('c'), ['a', 'b', 'd']);
});
test('a->b, b->c, b->d, b->e, d->f, e->f', function() {
this.graph.addDependency('a', 'b');
this.graph.addDependency('b', 'c');
this.graph.addDependency('b', 'd');
this.graph.addDependency('b', 'e');
this.graph.addDependency('d', 'f');
this.graph.addDependency('e', 'f');
assert.sameMembers(this.graph.getAllDependent('a'), []);
assert.sameMembers(this.graph.getAllDependent('b'), ['a']);
assert.sameMembers(this.graph.getAllDependent('c'), ['a', 'b']);
assert.sameMembers(this.graph.getAllDependent('d'), ['a', 'b']);
assert.sameMembers(this.graph.getAllDependent('e'), ['a', 'b']);
assert.sameMembers(this.graph.getAllDependent('f'), ['a', 'b', 'd', 'e']);
});
});
suite('throws when a circular dependency is detected', function() {
test('a->b, b->a', function() {
this.graph.addDependency('a', 'b');
assert.throw(() => {
this.graph.addDependency('b', 'a');
}, Error, 'circular dependency detected! b -> a -> b');
});
test('a->b, c->a, b->c', function() {
this.graph.addDependency('a', 'b');
this.graph.addDependency('c', 'a');
assert.throw(() => {
this.graph.addDependency('b', 'c');
}, Error, 'circular dependency detected! b -> c -> a -> b');
});
test('a->b, c->d, d->a, b->c', function() {
this.graph.addDependency('a', 'b');
this.graph.addDependency('c', 'd');
this.graph.addDependency('d', 'a');
assert.throw(() => {
this.graph.addDependency('b', 'c');
}, Error, 'circular dependency detected! b -> c -> d -> a -> b');
});
});
});

View file

@ -0,0 +1,98 @@
'use strict';
suite('EventEmitter', function() {
suiteSetup(function(done) {
testRequire(['modules/base/event_emitter'], (EventEmitter) => {
this.EventEmitter = EventEmitter;
done();
});
});
suite('constructor', function() {
test('should have an array for each event', function() {
var emitter = this.EventEmitter(['event1', 'event2']);
assert.isArray(emitter._eventListeners.event1);
assert.isArray(emitter._eventListeners.event2);
});
test('should throw when no valid event names', function() {
assert.throw(() => {
this.EventEmitter();
}, Error, 'no valid registered events');
});
});
suite('addEventListener', function() {
setup(function() {
this.emitter = this.EventEmitter(['event1', 'event2']);
});
suite('should call to the listener when emitting the event', function() {
test('register a function', function() {
var listener = sinon.spy();
this.emitter.addEventListener('event1', listener);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledWith(listener, sinon.match({
type: 'event1',
detail: 'value1'
}));
});
test('register an object', function() {
var eventHandler = {
handleEvent: sinon.spy()
};
this.emitter.addEventListener('event1', eventHandler);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledWith(eventHandler.handleEvent, sinon.match({
type: 'event1',
detail: 'value1'
}));
});
test('should only call once when registering multiple times', function() {
var listener = sinon.spy();
this.emitter.addEventListener('event1', listener);
this.emitter.addEventListener('event1', listener);
this.emitter.addEventListener('event1', listener);
this.emitter.addEventListener('event1', listener);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledWith(listener, sinon.match({
type: 'event1',
detail: 'value1'
}));
sinon.assert.calledOnce(listener);
});
});
});
suite('removeEventListener', function() {
setup(function() {
this.emitter = this.EventEmitter(['event1', 'event2']);
});
suite('should not call to the listener when it is removed', function() {
test('the listener is a function', function() {
var listener = sinon.spy();
this.emitter.addEventListener('event1', listener);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledOnce(listener);
this.emitter.removeEventListener('event1', listener);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledOnce(listener);
});
test('the listener is an object', function() {
var eventHandler = {
handleEvent: sinon.spy()
};
this.emitter.addEventListener('event1', eventHandler);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledOnce(eventHandler.handleEvent);
this.emitter.removeEventListener('event1', eventHandler);
this.emitter._emitEvent('event1', 'value1');
sinon.assert.calledOnce(eventHandler.handleEvent);
});
});
});
});

View file

@ -0,0 +1,207 @@
'use strict';
suite('Module', function() {
suiteSetup(function(done) {
testRequire(['modules/base/module'], (Module) => {
this.Module = Module;
done();
});
});
suite('create', function() {
test('constructor is called when instantiation', function() {
var constructor = sinon.spy();
var Module = this.Module.create(constructor);
Module();
assert.ok(constructor.called);
});
test('throws when the constructor is invalid', function() {
assert.throw(function() {
this.Module.create({});
}, Error);
});
test('name of the module is the name of the constructor', function() {
var constructor = function FakeModule() {};
var Module = this.Module.create(constructor);
assert.equal(Module().$name, constructor.name);
});
});
suite('Extendibility', function() {
suite('extend', function() {
var A, B, C;
var instanceOfA, instanceOfB, instanceOfC;
function executeTest() {
test('have individual properties', function() {
// Default values are the same
assert.equal(instanceOfC.propertyA, instanceOfA.propertyA);
assert.equal(instanceOfC.propertyB, instanceOfB.propertyB);
// Check whether they are individual.
instanceOfC.propertyA = 'valueA2';
instanceOfC.propertyB = 'valueB2';
assert.equal(instanceOfA.propertyA, 'valueA');
assert.equal(instanceOfB.propertyB, 'valueB');
});
test('share the same function ', function() {
assert.equal(instanceOfC.funcA, instanceOfA.funcA);
assert.equal(instanceOfC.funcB, instanceOfB.funcB);
});
}
setup(function() {
instanceOfA = A();
instanceOfB = B();
instanceOfC = C();
});
suite('extend from a single module', function() {
suiteSetup(function() {
A = this.Module.create(function() {
this.propertyA = 'valueA';
});
A.prototype.funcA = function() { return this.propertyA; };
B = this.Module.create(function() {
this.super(A).call(this);
this.propertyB = 'valueB';
}).extend(A);
B.prototype.funcB = function() { return this.propertyB; };
C = this.Module.create(function() {
this.super(B).call(this);
}).extend(B);
});
executeTest();
});
suite('extend from multiple modules', function() {
suiteSetup(function() {
A = this.Module.create(function() {
this.propertyA = 'valueA';
});
A.prototype.funcA = function() { return this.propertyA; };
B = this.Module.create(function() {
this.propertyB = 'valueB';
});
B.prototype.funcB = function() { return this.propertyB; };
C = this.Module.create(function() {
this.super(A).call(this);
this.super(B).call(this);
}).extend(A, B);
});
executeTest();
});
});
suite('super', function() {
var ctorA, ctorB;
var A, B;
setup(function() {
ctorA = sinon.spy();
ctorB = sinon.spy();
A = this.Module.create(ctorA);
B = this.Module.create(ctorB).extend(A);
});
test('able to call to the constructors of the extended modules',
function() {
var C = this.Module.create(function() {
this.super(A).call(this);
this.super(B).call(this);
}).extend(A, B);
C();
assert.ok(ctorA.called);
assert.ok(ctorB.called);
});
});
suite('logging', function() {
var module;
function doLog(obj) {
obj.debug('debug');
obj.info('info');
obj.warn('warn');
obj.error('error');
}
setup(function() {
this.sinon.stub(console, 'log');
this.sinon.stub(console, 'info');
this.sinon.stub(console, 'warn');
this.sinon.stub(console, 'error');
var Module = this.Module.create(function A() {});
module = Module();
});
test('NONE', function() {
module._logLevel = this.Module.LOG_LEVEL.NONE;
doLog(module);
assert.ok(console.log.notCalled);
assert.ok(console.info.notCalled);
assert.ok(console.warn.notCalled);
assert.ok(console.error.notCalled);
});
test('DEBUG', function() {
module._logLevel = this.Module.LOG_LEVEL.DEBUG;
doLog(module);
assert.ok(console.log.called);
assert.ok(console.info.notCalled);
assert.ok(console.warn.notCalled);
assert.ok(console.error.notCalled);
});
test('INFO', function() {
module._logLevel = this.Module.LOG_LEVEL.INFO;
doLog(module);
assert.ok(console.log.called);
assert.ok(console.info.called);
assert.ok(console.warn.notCalled);
assert.ok(console.error.notCalled);
});
test('WARN', function() {
module._logLevel = this.Module.LOG_LEVEL.WARN;
doLog(module);
assert.ok(console.log.called);
assert.ok(console.info.called);
assert.ok(console.warn.called);
assert.ok(console.error.notCalled);
});
test('ERROR && ALL', function() {
module._logLevel = this.Module.LOG_LEVEL.ERROR;
doLog(module);
assert.ok(console.log.called);
assert.ok(console.info.called);
assert.ok(console.warn.called);
assert.ok(console.error.called);
module._logLevel = this.Module.LOG_LEVEL.ALL;
doLog(module);
assert.ok(console.log.called);
assert.ok(console.info.called);
assert.ok(console.warn.called);
assert.ok(console.error.called);
});
});
});
});

View file

@ -0,0 +1,135 @@
'use strict';
suite('TaskScheduler >', function() {
setup(function(done) {
testRequire(['modules/base/task_scheduler'], (TaskScheduler) => {
this.taskScheduler = TaskScheduler();
done();
});
});
test('_lock()', function() {
this.taskScheduler._lock();
assert.ok(this.taskScheduler.isLocked,
'we will set internal lock to make sure it\'s locked');
});
test('_unlock()', function() {
this.sinon.stub(this.taskScheduler, '_executeNextTask');
this.taskScheduler._unlock();
assert.ok(this.taskScheduler._executeNextTask.called,
'we will release internal lock');
});
suite('_executeNextTask()', function() {
suite('if isLocked', function() {
setup(function() {
this.sinon.stub(this.taskScheduler._tasks, 'shift');
this.taskScheduler.isLocked = true;
this.taskScheduler._executeNextTask();
});
test('do nothing', function() {
assert.isFalse(this.taskScheduler._tasks.shift.called);
});
});
suite('if not locked, and task is resolved here', function() {
setup(function() {
this.taskScheduler.isLocked = false;
this.sinon.stub(this.taskScheduler, '_unlock');
this.taskScheduler._tasks = [{
func: function() {
return Promise.resolve();
},
defer: {
resolve: Promise.resolve.bind(Promise),
reject: Promise.reject.bind(Promise)
}
}];
});
test('we will do following works', function(done) {
this.taskScheduler._executeNextTask().then(() => {
assert.isTrue(this.taskScheduler._unlock.called);
}).then(done, done);
});
});
suite('if not locked, and task is rejected here', function() {
setup(function() {
this.taskScheduler.isLocked = false;
this.sinon.stub(this.taskScheduler, '_unlock');
this.taskScheduler._tasks = [{
func: function() {
return Promise.reject();
},
defer: {
resolve: Promise.resolve.bind(Promise),
reject: Promise.reject.bind(Promise)
}
}];
});
test('we will do following works', function(done) {
this.taskScheduler._executeNextTask().then(() => {
assert.isTrue(this.taskScheduler._unlock.called);
}).then(done, done);
});
});
});
suite('_removeRedundantTasks()', function() {
test('we will drop same-type tasks', function() {
this.taskScheduler._tasks = [
{ cancelable: true, type: 'type1' },
{ cancelable: true, type: 'type1' },
{ cancelable: true, type: 'type1' },
{ cancelable: true, type: 'type2' }
];
var leftTasks = this.taskScheduler._removeRedundantTasks('type1');
assert.equal(leftTasks.length, 1);
assert.equal(leftTasks[0].type, 'type2');
});
test('we will keep cancelable:false tasks and drop same-type tasks',
function() {
this.taskScheduler._tasks = [
{ cancelable: false, type: 'type1' },
{ cancelable: false, type: 'type1' },
{ cancelable: true, type: 'type1' }, // this will be dropped
{ cancelable: true, type: 'type2' }
];
var leftTasks = this.taskScheduler._removeRedundantTasks('type1');
assert.equal(leftTasks.length, 3);
});
});
suite('enqueue()', function() {
setup(function() {
this.sinon.spy(this.taskScheduler, '_executeNextTask');
this.sinon.spy(this.taskScheduler, '_removeRedundantTasks');
});
suite('if no task.func', function() {
test('we will do nothing', function(done) {
this.taskScheduler.enqueue({}).then(() => {
assert.isFalse(this.taskScheduler._executeNextTask.called);
}).then(done, done);
});
});
suite('if we have task.func', function() {
test('we will do following works', function(done) {
this.taskScheduler.enqueue({
type: 'type1',
func: function() {
return Promise.resolve();
}
}).then(() => {
assert.isTrue(this.taskScheduler._executeNextTask.called);
assert.isTrue(this.taskScheduler._removeRedundantTasks.called);
}).then(done, done);
});
});
});
});