UNPKG

@informalsystems/quint

Version:

Core tool for the Quint specification language

211 lines 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const mocha_1 = require("mocha"); const chai_1 = require("chai"); const inferrer_1 = require("../../src/effects/inferrer"); const modeChecker_1 = require("../../src/effects/modeChecker"); const quintError_1 = require("../../src/quintError"); const errorTree_1 = require("../../src/errorTree"); const util_1 = require("../util"); (0, mocha_1.describe)('checkModes', () => { const baseDefs = ['var x: int', 'var y: bool']; function checkMockedDefs(defs) { const text = `module A { const c: int } module wrapper { ${baseDefs.concat(defs).join('\n')} }`; const { modules, table } = (0, util_1.parseMockedModule)(text); const wrapper = modules.find(m => m.name === 'wrapper'); const inferrer = new inferrer_1.EffectInferrer(table); const [errors, effects] = inferrer.inferEffects(wrapper.declarations); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(errorTree_1.errorTreeToString)}`); const modeChecker = new modeChecker_1.ModeChecker(); return modeChecker.checkModes(wrapper.declarations, effects); } (0, mocha_1.it)('finds mode errors between action and def', () => { const defs = [`def a(p) = x' = p`]; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 13n, { message: "def operators may only read state variables, but operator `a` updates variables 'x'. Use action instead.", code: 'QNT200', reference: 13n, data: { fix: { kind: 'replace', original: 'def', replacement: 'action' } }, }, ], ]); }); (0, mocha_1.it)('finds no errors for correct action', () => { const defs = [`action a(p) = x' = p`]; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.deepEqual(suggestions.size, 0); }); (0, mocha_1.it)('finds no errors for pure def using polymorphic operator', () => { const defs = [`pure def a(p) = if (not(p > 1)) p else p + 1`]; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.deepEqual(suggestions.size, 0); }); (0, mocha_1.it)('finds suggestions for def with action annotation', () => { const defs = ['action a(p) = x + p']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.sameDeepMembers([...suggestions.entries()], [[13n, 'def']]); }); (0, mocha_1.it)('finds mode errors between pureval and val', () => { const defs = ['pure val v = x + 1']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 11n, { message: "pure val operators may not interact with state variables, but operator `v` reads variables 'x'. Use val instead.", code: 'QNT200', reference: 11n, data: { fix: { kind: 'replace', original: 'pure val', replacement: 'val' } }, }, ], ]); }); (0, mocha_1.it)('finds suggestions for pure val with val annotation', () => { const defs = ['val a = 1']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.sameDeepMembers([...suggestions.entries()], [[9n, 'pureval']]); }); (0, mocha_1.it)('finds mode errors between puredef and def', () => { const defs = ['pure def f(p) = not(y)']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 12n, { message: "pure def operators may not interact with state variables, but operator `f` reads variables 'y'. Use def instead.", code: 'QNT200', reference: 12n, data: { fix: { kind: 'replace', original: 'pure def', replacement: 'def' } }, }, ], ]); }); (0, mocha_1.it)('finds suggestions for pure def with def annotation', () => { const defs = ['def a(p) = p']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.sameDeepMembers([...suggestions.entries()], [[11n, 'puredef']]); }); (0, mocha_1.it)('finds mode errors between val and temporal', () => { const defs = ['pure val v = always(x > 5)']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 12n, { message: "pure val operators may not interact with state variables, but operator `v` performs temporal operations over variables 'x'. Use temporal instead.", code: 'QNT200', reference: 12n, data: { fix: { kind: 'replace', original: 'pure val', replacement: 'temporal' } }, }, ], ]); }); (0, mocha_1.it)('finds errors when an instance override is not pure', () => { const defs = ['import A(c = x) as A1']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 8n, { message: "Instance overrides must be pure, but the value for c reads variables 'x'", code: 'QNT201', reference: 8n, data: {}, }, ], ]); }); (0, mocha_1.it)('allows operators as override values', () => { const defs = ['def f(p) = p + 1', 'import A(c = f) as A1']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); }); (0, mocha_1.it)('finds errors in nested definitions', () => { const defs = ['pure val a = { val m = x + 1 { m } }']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 14n, { message: "pure val operators may not interact with state variables, but operator `a` reads variables 'x'. Use val instead.", code: 'QNT200', reference: 14n, data: { fix: { kind: 'replace', original: 'pure val', replacement: 'val' } }, }, ], ]); }); (0, mocha_1.it)('finds no error with proper high order operators', () => { const defs = ['pure def c(p, f) = Set(p).map(f)']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.deepEqual(suggestions.size, 0); }); (0, mocha_1.it)('keeps track of parameters in nested definitions', () => { const defs = ['pure def f(p) = { pure def m(q) = p + 1 { m(1) } }']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.deepEqual(suggestions.size, 0); }); (0, mocha_1.it)('finds correct equalities between entity unions (#808)', () => { const defs = ['pure def foo(s: Set[int]): bool = { tuples(s, s).forall( ((a,b)) => (a + b).in(s)) }']; const [errors, suggestions] = checkMockedDefs(defs); chai_1.assert.isEmpty(errors, `Should find no errors, found: ${[...errors.values()].map(quintError_1.quintErrorToString)}`); chai_1.assert.deepEqual(suggestions.size, 0); }); (0, mocha_1.it)('complains about parameters on pure val vs pure def', () => { const defs = ['pure val foo(p) = p + 1']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 13n, { message: 'pure val operators may not have parameters, but operator `foo` has 1 parameter. Use pure def instead.', code: 'QNT200', reference: 13n, data: { fix: { kind: 'replace', original: 'pure val', replacement: 'pure def' } }, }, ], ]); }); (0, mocha_1.it)('complains about parameters on val vs def', () => { const defs = ['val foo(p) = p + 1']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 13n, { message: 'val operators may not have parameters, but operator `foo` has 1 parameter. Use def instead.', code: 'QNT200', reference: 13n, data: { fix: { kind: 'replace', original: 'val', replacement: 'def' } }, }, ], ]); }); (0, mocha_1.it)('prioritizes messages about effects over parameters', () => { const defs = ['pure val foo(p) = p + x']; const [errors, _suggestions] = checkMockedDefs(defs); chai_1.assert.sameDeepMembers([...errors.entries()], [ [ 13n, { message: "pure val operators may not interact with state variables, but operator `foo` reads variables 'x'. Use def instead.", code: 'QNT200', reference: 13n, data: { fix: { kind: 'replace', original: 'pure val', replacement: 'def' } }, }, ], ]); }); }); //# sourceMappingURL=modeChecker.test.js.map