stsys
Version:
String rewriting system (semi-Thue system)
298 lines (283 loc) • 10 kB
JavaScript
const assert = require('assert');
const createProver = require('../lib/prover').createProver;
describe('Prover creation', function(){
it('creation failing (missing axioms)', function(){
try
{
createProver();
}
catch (error)
{
assert.equal(error.message,'missing axioms');
return;
}
assert.fail('expected exception not thrown');
});
it('creation failing (no axioms)', function(){
try
{
createProver([]);
}
catch (error)
{
assert.equal(error.message,'no axioms (empty Array)');
return;
}
assert.fail('expected exception not thrown');
});
it('creation failing (invalid specification)', function(){
try
{
createProver(42);
}
catch (error)
{
assert.equal(error.message,'invalid specification of axioms (neither Array nor string)');
return;
}
assert.fail('expected exception not thrown');
});
it('creation failing (invalid characters)', function(){
try
{
createProver('abc = #');
}
catch (error)
{
assert.equal(error.message,'invalid string pair (illegal characters): abc = #');
return;
}
assert.fail('expected exception not thrown');
});
it('creation failing (missing equality character)', function(){
try
{
createProver(['a = bc', 'abc']);
}
catch (error)
{
assert.equal(error.message,'invalid string pair (missing equality): abc');
return;
}
assert.fail('expected exception not thrown');
});
it('creation succeeding', function(){
['ab = ba', ['aba = ba', 'baa = ba', 'aaa = ']].forEach(function(ax){
const prover = createProver(ax);
assert.ok(prover);
assert.equal(prover.getOrdering(), undefined);
assert.equal(prover.getPreorder(), undefined);
assert.equal(prover.getState(), null);
assert.equal(prover.getRulesCount(), 0);
assert.deepEqual(prover.getRules(), []);
assert.deepEqual(prover.getGoals(), []);
assert.equal(prover.getTotalGoalsCount(), 0);
assert.equal(prover.getProvedGoalsCount(), 0);
assert.deepEqual(prover.getAxioms(), typeof ax === 'string' ? [ax] : ax);
assert.equal(prover.getTotalCpCount(), 0);
assert.equal(prover.getStatistics(), null);
assert.ok(!prover.getStatisticsAsString());
});
});
});
describe('Prover runs', function(){
it('running to completion', function(){
const prover = createProver(['ab = ba', 'aba = ba']);
assert.equal(prover.run({ordering:'lex', preorder:['a', 'b']}), 'completed');
assert.equal(prover.getOrdering(), 'lex');
assert.deepEqual(prover.getPreorder(), ['a', 'b']);
assert.equal(prover.getState(), 'completed');
assert.equal(prover.getRulesCount(), 2);
assert.deepEqual(prover.getRules(), ['ab -> ba', 'baa -> ba']);
assert.equal(prover.getTotalCpCount(), 0);
assert.ok(prover.getHrtimeElapsed());
assert.ok(/^\d+ms$/.test(prover.getTimeElapsed()));
});
it('stopped, resumed, and rerun', function(){
const prover = createProver(['a = b', 'aab = c', 'aa =']);
assert.equal(prover.run({ordering:'lex', preorder:['a', 'c', 'b'], maxRuleGen:2}), 'stopped');
assert.equal(prover.getState(), 'stopped');
assert.equal(prover.getStatistics(), null);
assert.equal(prover.getRulesCount(), 2);
assert.equal(prover.getTotalCpCount(), 1);
assert.ok(prover.getHrtimeElapsed());
assert.ok(/^\d+ms$/.test(prover.getTimeElapsed()));
assert.equal(prover.run({statistics:true}), 'completed');
assert.equal(prover.getState(), 'completed');
assert.equal(prover.getStatistics(), null);
assert.equal(prover.getRulesCount(), 3);
assert.equal(prover.getTotalCpCount(), 0);
assert.deepEqual(prover.getRules(), ['a -> b', 'bb -> ', 'c -> b']);
assert.equal(prover.run(), 'completed');
assert.equal(prover.getState(), 'completed');
assert.equal(prover.getRulesCount(), 3);
assert.equal(prover.getTotalCpCount(), 0);
assert.equal(prover.rerun({
ordering:'lex',
preorder:['a', 'c', 'b'],
maxRuleGen:2,
statistics:true}), 'stopped');
assert.equal(prover.getState(), 'stopped');
assert.equal(prover.getRulesCount(), 2);
assert.equal(prover.getTotalCpCount(), 1);
let stats = prover.getStatistics();
assert.ok(stats);
assert.equal(stats.rulesGenerated, 2);
assert.equal(typeof (stats = prover.getStatisticsAsString()), 'string');
assert.ok(/Rules generated\s*:\s+2/.test(stats));
assert.equal(prover.rerun({ordering:'lex', preorder:['a', 'c', 'b'], maxRuleGen:1}), 'stopped');
assert.equal(prover.getState(), 'stopped');
assert.equal(prover.getRulesCount(), 1);
assert.equal(prover.getTotalCpCount(), 2);
assert.equal(prover.getStatistics(), null);
assert.ok(!prover.getStatisticsAsString());
});
it('run with changed ordering/preorder', function(){
const prover = createProver(['ab=ba', 'aba=ba'], {
ordering: 'lex',
preorder: ['b','a']
});
assert.deepEqual(prover.getPreorder(), ['b','a']);
assert.equal(prover.run({preorder:['a','b']}), 'completed');
assert.deepEqual(prover.getPreorder(), ['a','b']);
assert.equal(prover.getOrdering(), 'lex');
assert.equal(prover.rerun({ordering:'lpo'}), 'completed');
assert.deepEqual(prover.getPreorder(), ['a','b']);
assert.equal(prover.getOrdering(), 'lpo');
});
it('timed out', function(){
const prover = createProver('aba = ba');
assert.ok(prover);
assert.equal(prover.run({ordering:'lex', preorder:['a', 'b'], timeout:10}), 'stopped');
assert.ok(/^[12]\dms$/.test(prover.getTimeElapsed()));
assert.ok(prover.getRulesCount() > 1);
assert.ok(prover.getTotalCpCount() > 1);
let b = 1;
prover.getRules().forEach(function(rule){
const i = rule.indexOf('->');
const left = rule.substring(0, i - 1);
const right = rule.substring(i + 3);
assert.equal('a' + right, left);
assert.ok(new RegExp('^b{' + b++ + '}a$').test(right));
});
});
it('running until all goals are proved', function(){
const prover = createProver('ba = aba');
assert.equal(prover.run({
ordering:'lex',
preorder:['a', 'b'],
goals:['abbba = bbba', 'abbbbba = bbbbba']
}), 'proved');
assert.equal(prover.getTotalGoalsCount(), 2);
assert.equal(prover.getProvedGoalsCount(), 2);
const goals = prover.getGoals();
assert.ok(goals instanceof Array);
assert.equal(goals.length, 2);
goals.forEach(function(g){
assert.equal(typeof g.goal, 'string');
assert.equal(typeof g.proved, 'boolean');
assert.ok(g.proved);
assert.equal(typeof g.provedBy, 'string');
});
});
it('resuming to completion after clearing goals', function()
{
const prover = createProver(['ab=ba', 'aba=ba'], {
ordering: 'lex',
preorder: ['a','b']
});
assert.equal(prover.run({goals:['aab = ba']}), 'proved');
assert.equal(prover.run(), 'proved');
prover.clearGoals();
assert.equal(prover.run(), 'completed');
});
it('logging', function(){
const log1 = [];
const log2 = [];
const logger1 = function(s){
log1.push(s);
};
const logger2 = function(s){
log2.push(s);
};
let prover = createProver(['ab=ba', 'aba=ba'], {
logger: logger1,
logLevel: 2,
ordering: 'lex',
preorder: ['a','b']
});
assert.equal(prover.getOrdering(), 'lex');
assert.deepEqual(prover.getPreorder(), ['a','b']);
assert.equal(prover.run(), 'completed');
assert.equal(log1.length, 2);
assert.equal(log1[0], 'Ordering: Length/lexicographic ordering using preorder a > b');
assert.equal(log1[1], 'Running...');
log1.length = 0;
assert.equal(prover.rerun({logLevel: 3}), 'completed');
assert.equal(log1.length, 4);
assert.equal(log1[0], 'Ordering: Length/lexicographic ordering using preorder a > b');
assert.equal(log1[1], 'Running...');
assert.equal(log1[2], 'New rule #1: ab -> ba');
assert.equal(log1[3], 'New rule #2: baa -> ba');
log1.length = 0;
assert.equal(prover.rerun({logger:logger2}), 'completed');
assert.equal(log1.length, 0);
assert.equal(log2.length, 4);
prover = createProver(['ab=ba', 'aba=ba'], {
ordering: 'lex',
preorder: ['a','b']
});
prover.run({logLevel:5});
assert.equal(log1.length, 0);
assert.equal(log2.length, 4);
prover.rerun({logger:logger1, logLevel:0});
assert.equal(log1.length, 0);
prover.rerun({logLevel:3});
assert.deepEqual(log1, log2);
log1.length = 0;
prover = createProver('abba=bba', {
logger: logger1,
logLevel: 3,
ordering: 'lex',
preorder: ['a','b']
});
assert.equal(prover.run({maxRuleGen:5}), 'stopped');
let n = log1.length;
assert.ok(n > 5);
assert.equal(prover.run({maxRuleGen:5, logLevel:0}), 'stopped');
assert.equal(log1.length, n);
assert.equal(prover.run({maxRuleGen:5, logLevel:3}), 'stopped');
assert.ok(log1.length - n > 5);
n = log1.length;
log2.length = 0;
assert.equal(prover.run({maxRuleGen:5, logger:logger2}), 'stopped');
assert.equal(log1.length, n);
assert.ok(log2.length > 5);
});
it('failing due to missing/incomplete ordering data', function(){
let prover = createProver(['ab=ba', 'aba=ba'], {ordering: 'lpo'});
let exceptionThrown = false;
try
{
prover.run({preorder:['a', 'b']});
}
catch (error)
{
exceptionThrown = true;
assert.equal(error.message, 'no ordering specified');
}
assert.ok(exceptionThrown);
prover = createProver(['ab=ba', 'aba=ba'], {preorder:['a', 'b']});
exceptionThrown = false;
try
{
prover.run({ordering:'syl-r'});
}
catch (error)
{
exceptionThrown = true;
assert.equal(error.message, 'invalid preorder: non-empty array of letters expected');
}
assert.ok(exceptionThrown);
});
});