@informalsystems/quint
Version:
Core tool for the Quint specification language
229 lines • 14.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mocha_1 = require("mocha");
const chai_1 = require("chai");
const ir_1 = require("../builders/ir");
const collector_1 = require("../../src/names/collector");
const IRVisitor_1 = require("../../src/ir/IRVisitor");
const base_1 = require("../../src/names/base");
const idGenerator_1 = require("../../src/idGenerator");
(0, mocha_1.describe)('NameCollector', () => {
const baseModule = (0, ir_1.buildModuleWithDecls)(['def a = 1', 'def b = 2', 'def c = 3', 'const c1: int', 'const c2: int', 'type T = int', 'type R'], 'test_module', idGenerator_1.zerog);
function collect(module) {
const collector = new collector_1.NameCollector();
(0, IRVisitor_1.walkModule)(collector, baseModule);
(0, IRVisitor_1.walkModule)(collector, module);
return [collector.errors, collector.definitionsByName];
}
(0, mocha_1.describe)('existing modules', () => {
(0, mocha_1.it)('imports named definitions', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.a'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.deepInclude([...definitions.keys()], 'a');
chai_1.assert.notDeepInclude([...definitions.keys()], 'b');
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'a')?.importedFrom?.kind, 'import');
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'a')?.namespaces ?? [], []);
});
(0, mocha_1.it)('imports all definitions', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.includeDeepMembers([...definitions.keys()], ['a', 'b', 'T']);
});
(0, mocha_1.it)('imports definitions with namespace', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
const def = (0, base_1.getTopLevelDef)(definitions, 'test_module::a');
chai_1.assert.isTrue(def.hidden);
chai_1.assert.deepEqual(def?.kind, 'def');
});
(0, mocha_1.it)('imports definitions with qualifier', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module as my_import'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
const def = (0, base_1.getTopLevelDef)(definitions, 'my_import::a');
chai_1.assert.isTrue(def.hidden);
chai_1.assert.deepEqual(def?.kind, 'def');
});
(0, mocha_1.it)('instantiates modules', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module(c1 = 3, c2 = 4) as test_module_instance'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.includeDeepMembers([...definitions.keys()], ['test_module_instance::c1', 'test_module_instance::c2']);
chai_1.assert.includeDeepMembers([...definitions.keys()], ['test_module_instance::T']);
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'test_module_instance::a')?.importedFrom?.kind, 'instance');
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'test_module_instance::a')?.namespaces ?? [], [
'test_module_instance',
'wrapper',
]);
});
(0, mocha_1.it)('fails instantiating when a param does not exists', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module(c1 = 3, c2 = 4, other = 5) as test_module_instance'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT406',
message: "Instantiation error: 'other' not found in 'test_module'",
reference: 0n,
data: {},
},
]);
});
(0, mocha_1.it)('fails instantiating when a param is not a constant', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module(c1 = 3, c2 = 4, a = 5) as test_module_instance'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT406',
message: "Instantiation error: 'a' is not a constant in 'test_module'",
reference: 0n,
data: {},
},
]);
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'test_module_instance::a')?.kind, 'def');
});
(0, mocha_1.it)('fails importing itself', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import wrapper.*', 'import wrapper(c1 = 1) as w', 'export wrapper.*'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT407', message: "Cannot import 'wrapper' inside 'wrapper'", reference: 0n, data: {} },
{ code: 'QNT407', message: "Cannot instantiate 'wrapper' inside 'wrapper'", reference: 0n, data: {} },
{ code: 'QNT407', message: "Cannot export 'wrapper' inside 'wrapper'", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('exports all definitions', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['export test_module.*'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'T').hidden);
});
(0, mocha_1.it)('exports previously imported definitions', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*', 'export test_module.*'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'T').hidden);
});
(0, mocha_1.it)('exports imported definitions that were previously qualified', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module as T1', 'export T1.*'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'T').hidden);
});
(0, mocha_1.it)('exports specific definitions', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*', 'export test_module.a'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
// a is not hidden anymore
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
// T is still hidden
chai_1.assert.isTrue((0, base_1.getTopLevelDef)(definitions, 'T').hidden);
});
(0, mocha_1.it)('exports definitions with qualifier', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*', 'export test_module as my_export'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'my_export::a').hidden);
});
(0, mocha_1.it)('exports definitions with namespace', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*', 'export test_module'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isTrue((0, base_1.getTopLevelDef)(definitions, 'a').hidden);
chai_1.assert.isNotTrue((0, base_1.getTopLevelDef)(definitions, 'test_module::a').hidden);
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'a')?.importedFrom?.kind, 'import');
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'test_module::a')?.importedFrom?.kind, 'export');
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'a')?.namespaces ?? [], []);
chai_1.assert.deepEqual((0, base_1.getTopLevelDef)(definitions, 'test_module::a')?.namespaces ?? [], ['test_module']);
});
(0, mocha_1.it)('fails exporting unexisting definition', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module.*', 'export test_module.other'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT404', message: "Name 'test_module::other' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('does not collect nested defs inside assume', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['assume _ = val foo = 1 { foo }'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isFalse(definitions.has('foo'));
});
(0, mocha_1.it)('does not collect nested defs inside instances', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import test_module(c1 = (val foo = 1 { foo })).*'], undefined, idGenerator_1.zerog);
const [errors, definitions] = collect(quintModule);
chai_1.assert.isEmpty(errors);
chai_1.assert.isFalse(definitions.has('foo'));
});
});
(0, mocha_1.describe)('conflicts', () => {
(0, mocha_1.it)('reports conflicts with builtin names', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['def size(x) = 10'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT101', message: "Built-in name 'size' is redefined in module 'wrapper'", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('reports conflicts with user defined names', () => {
// Use the real id generator to have different references for each def
const quintModule = (0, ir_1.buildModuleWithDecls)(['def a = 10', 'import test_module.*']);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT101',
message: "Conflicting definitions found for name 'a' in module 'wrapper'",
reference: 2n,
data: {},
},
{
code: 'QNT101',
message: "Conflicting definitions found for name 'a' in module 'wrapper'",
reference: 0n,
data: {},
},
]);
});
(0, mocha_1.it)('reports conflicts with module names', () => {
// Setup already defines a module named 'test_module', see `baseDefs`
const quintModule = (0, ir_1.buildModuleWithDecls)(['def a = 10'], 'test_module');
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{
code: 'QNT102',
message: "Module with name 'test_module' was already defined",
reference: 3n,
data: {},
},
]);
});
});
(0, mocha_1.describe)('unexisting modules', () => {
(0, mocha_1.it)('fails importing', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import unexisting_module.*'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('fails instantiating', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['import unexisting_module(c1 = c1, c2 = c2) as test_module_instance'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} },
]);
});
(0, mocha_1.it)('fails exporting', () => {
const quintModule = (0, ir_1.buildModuleWithDecls)(['export unexisting_module.*'], undefined, idGenerator_1.zerog);
const [errors, _definitions] = collect(quintModule);
chai_1.assert.sameDeepMembers(errors, [
{ code: 'QNT405', message: "Module 'unexisting_module' not found", reference: 0n, data: {} },
]);
});
});
});
//# sourceMappingURL=collector.test.js.map