@informalsystems/quint
Version:
Core tool for the Quint specification language
107 lines (104 loc) • 5.04 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const src_1 = require("../../src");
const NondetChecker_1 = require("../../src/effects/NondetChecker");
const inferrer_1 = require("../../src/types/inferrer");
(0, mocha_1.describe)('checkNondets', () => {
function parseAndTypecheck(text) {
const idGen = (0, src_1.newIdGenerator)();
const fake_path = { normalizedPath: 'fake_path', toSourceName: () => 'fake_path' };
const { modules, table, errors } = (0, src_1.parse)(idGen, 'fake_location', fake_path, text);
chai_1.assert.isEmpty(errors, `Unexpected parse errors: ${[...errors].map(src_1.quintErrorToString)}`);
const typeInferrer = new inferrer_1.TypeInferrer(table);
const [typeErrors, types] = typeInferrer.inferTypes(modules[0].declarations);
chai_1.assert.isEmpty(typeErrors, `Unexpected type errors: ${[...typeErrors.values()].map(src_1.errorTreeToString)}`);
return { module: modules[0], table, types };
}
(0, mocha_1.it)('returns empty map for effects with no problems', () => {
const text = `module A {
val a = 1
var x: int
action foo = { nondet bar = Set(1,2).oneOf() x' = bar }
}`;
const { module, table, types } = parseAndTypecheck(text);
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(src_1.quintErrorToString)}`);
});
(0, mocha_1.it)('finds an error when oneOf is used in a val', () => {
const text = `module A {
val a = Set(1,2).oneOf()
}`;
const { module, table, types } = parseAndTypecheck(text);
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT203', message: "'oneOf' must be used inside a nondet definition", reference: 4n, data: {} },
]);
});
(0, mocha_1.it)('finds an error when oneOf is not the outermost expression', () => {
const text = `module A {
var x: int
action foo = { nondet bar = Set(1,2).oneOf() + 1 { x' = bar } }
}`;
const { module, table, types } = parseAndTypecheck(text);
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT204',
message: "the outermost expression in a nondet definition must be either 'oneOf' or 'apalache::generate'",
reference: 8n,
data: {},
},
]);
});
(0, mocha_1.it)('find an error when nondet is a top-level definition', () => {
const text = `module A {
var x: int
nondet top_level = Set(1,2).oneOf()
}`;
const { module, table, types } = parseAndTypecheck(text);
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT206',
message: "'nondet' can only be used inside actions, not at the top level",
reference: 7n,
data: {},
},
]);
});
(0, mocha_1.it)('finds an error when the scope expression for the nondet binding is not boolean', () => {
// FIXME: ideally this should also complain about the top-level def not
// being an action. This requires the introduction of a new effect, which is
// not trivial. For now, checking for boolean returns should already help a
// lot.
const text = `module A {
// error: nondet bindings can only be used with boolean expressions
val non_action = { nondet bar = Set(1,2).oneOf() bar }
}`;
const { module, table, types } = parseAndTypecheck(text);
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT205',
message: 'nondet bindings can only be used with boolean expressions, but expression has type: int',
reference: 7n,
data: {},
},
]);
});
(0, mocha_1.it)('can survive missing types and lookup table entries', () => {
const text = `module A {
var x: int
nondet top_level = Set(1,2).oneOf()
val non_action = { nondet bar = Set(1,2).oneOf() bar }
}`;
const { module } = parseAndTypecheck(text);
const table = new Map();
const types = new Map();
const errors = new NondetChecker_1.NondetChecker(table).checkNondets(types, module.declarations);
chai_1.assert.sameDeepMembers(errors, []);
});
});
//# sourceMappingURL=NondetChecker.test.js.map