From 1f72ef77c4e3df35f807d2f9c8735ce3761048cf Mon Sep 17 00:00:00 2001 From: "John J. Camilleri" Date: Mon, 4 Oct 2021 15:07:23 +0200 Subject: [PATCH] Add bootNGF. Organise tests better. --- .github/workflows/build-majestic.yml | 1 + src/runtime/javascript/index.ts | 34 +++++--- src/runtime/javascript/tests/basic.test.ts | 96 +++++++++++++++++----- src/runtime/python/tests/test_basic.py | 10 +-- 4 files changed, 103 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build-majestic.yml b/.github/workflows/build-majestic.yml index 4acfc244b..376344b4a 100644 --- a/.github/workflows/build-majestic.yml +++ b/.github/workflows/build-majestic.yml @@ -61,6 +61,7 @@ jobs: working-directory: ./src/runtime/javascript env: LD_LIBRARY_PATH: /usr/local/lib + PYTHON: /usr/bin/python2 run: | npm ci npm run test diff --git a/src/runtime/javascript/index.ts b/src/runtime/javascript/index.ts index 287e42b85..42c3fb05d 100644 --- a/src/runtime/javascript/index.ts +++ b/src/runtime/javascript/index.ts @@ -64,6 +64,8 @@ interface Pointer extends Buffer { class PGFError extends Error { constructor(message: string) { super(message) + // https://stackoverflow.com/a/65243177/98600 + Object.setPrototypeOf(this, PGFError.prototype) } } @@ -147,17 +149,17 @@ function PgfText_AsString (txtPtr: Pointer) { // ---------------------------------------------------------------------------- // PGF grammar object -class PGF { - db: Pointer - revision: number +export class PGFGrammar { + readonly db: Pointer + readonly revision: number - constructor () { - this.db = ref.NULL_POINTER as Pointer - this.revision = 0 + constructor (db: Pointer, revision: number) { + this.db = db + this.revision = revision } // NB the library user is responsible for calling this - destructor () { + release () { runtime.pgf_free_revision(this.db, this.revision) } @@ -199,23 +201,29 @@ class PGF { // ---------------------------------------------------------------------------- // PGF module functions -function readPGF (path: string): PGF { +function readPGF (path: string): PGFGrammar { const rev = ref.alloc(PgfRevision) as Pointer const err = ref.alloc(PgfExn) as Pointer const db = runtime.pgf_read_pgf(path, rev, err) handleError(err) + return new PGFGrammar(db, rev.deref()) +} - const state = new PGF() - state.db = db - state.revision = rev.deref() - return state +function bootNGF (pgf_path: string, ngf_path: string): PGFGrammar { + const rev = ref.alloc(PgfRevision) as Pointer + const err = ref.alloc(PgfExn) as Pointer + const db = runtime.pgf_boot_ngf(pgf_path, ngf_path, rev, err) + handleError(err) + return new PGFGrammar(db, rev.deref()) } // ---------------------------------------------------------------------------- // Exposed library API export default { - readPGF + PGFError, + readPGF, + bootNGF } // ---------------------------------------------------------------------------- diff --git a/src/runtime/javascript/tests/basic.test.ts b/src/runtime/javascript/tests/basic.test.ts index 26bd6eeb2..e0c60674a 100644 --- a/src/runtime/javascript/tests/basic.test.ts +++ b/src/runtime/javascript/tests/basic.test.ts @@ -1,30 +1,86 @@ -import PGF from '../index' +import PGF, { PGFGrammar } from '../index' +import fs from 'fs' -// readPGF +describe('readPGF', () => { + test('valid', () => { + PGF.readPGF('../haskell/tests/basic.pgf') + }) -test('readPGF successful', () => { - let gr = PGF.readPGF('../haskell/tests/basic.pgf') + test('non-existent', () => { + expect(() => { + PGF.readPGF('../haskell/tests/abc.pgf') + }).toThrow(Error) + }) + + test('GF', () => { + expect(() => { + PGF.readPGF('../haskell/tests/basic.gf') + }).toThrow(PGF.PGFError) + }) + + // test('NGF', () => { + // expect(() => { + // PGF.readPGF('basic.ngf') + // }).toThrow(PGF.PGFError) + // }) }) -test('readPGF missing file', () => { - expect(() => { - PGF.readPGF('abc.pgf') - }).toThrow() +describe('bootNGF', () => { + beforeAll(() => { + try { + fs.unlinkSync('./basic.ngf') + } catch { } + }) + + test('valid', () => { + PGF.bootNGF('../haskell/tests/basic.pgf', './basic.ngf') + }) + + test('non-existent', () => { + expect(() => { + PGF.bootNGF('../haskell/tests/abc.pgf', './abc.ngf') + }).toThrow(Error) + }) + + test('GF', () => { + expect(() => { + PGF.bootNGF('../haskell/tests/basic.gf', './abc.ngf') + }).toThrow(PGF.PGFError) + }) + + test('NGF', () => { + expect(() => { + PGF.bootNGF('./basic.ngf', './abc.ngf') + }).toThrow(PGF.PGFError) + }) + + test('existing', () => { + expect(() => { + PGF.bootNGF('../haskell/tests/basic.pgf', './basic.ngf') + }).toThrow(Error) + }) }) -// abstract syntax +describe('abstract syntax', () => { + let gr: PGFGrammar -test('abstract name', () => { - let gr = PGF.readPGF('../haskell/tests/basic.pgf') - expect(gr.getAbstractName()).toBe('basic') -}) + beforeAll(() => { + gr = PGF.readPGF('../haskell/tests/basic.pgf') + }) -test('categories', () => { - let gr = PGF.readPGF('../haskell/tests/basic.pgf') - expect(gr.getCategories()).toEqual(['Float','Int','N','P','S','String']) -}) + afterAll(() => { + gr.release() + }) -test('functions', () => { - let gr = PGF.readPGF('../haskell/tests/basic.pgf') - expect(gr.getFunctions()).toEqual(['c','ind','s','z']) + test('abstract name', () => { + expect(gr.getAbstractName()).toBe('basic') + }) + + test('categories', () => { + expect(gr.getCategories()).toEqual(['Float','Int','N','P','S','String']) + }) + + test('functions', () => { + expect(gr.getFunctions()).toEqual(['c','ind','s','z']) + }) }) diff --git a/src/runtime/python/tests/test_basic.py b/src/runtime/python/tests/test_basic.py index e0daebb14..d594d42ad 100644 --- a/src/runtime/python/tests/test_basic.py +++ b/src/runtime/python/tests/test_basic.py @@ -8,7 +8,7 @@ from pgf import * def PGF(): return readPGF("../haskell/tests/basic.pgf") -def test_readPGF_non_existant(): +def test_readPGF_non_existent(): with pytest.raises(FileNotFoundError): readPGF("../haskell/tests/abc.pgf") @@ -28,7 +28,7 @@ def NGF(): yield ngf os.remove("./basic.ngf") -def test_bootNGF_non_existant(): +def test_bootNGF_non_existent(): with pytest.raises(FileNotFoundError): bootNGF("../haskell/tests/abc.pgf", "./abc.ngf") @@ -46,7 +46,7 @@ def test_bootNGF_existing(NGF): # readNGF -def test_readNGF_non_existant(): +def test_readNGF_non_existent(): with pytest.raises(FileNotFoundError): readNGF("./abc.ngf") @@ -100,7 +100,7 @@ def test_functionsByCat_1(PGF): def test_functionsByCat_2(PGF): assert PGF.functionsByCat("S") == ["c"] -def test_functionsByCat_non_existant(PGF): +def test_functionsByCat_non_existent(PGF): assert PGF.functionsByCat("X") == [] def test_categoryContext_1(PGF): @@ -169,7 +169,7 @@ def test_functionType_2(PGF): def test_functionType_3(PGF): assert PGF.functionType("c") == readType("N -> S") -def test_functionType_non_existant(PGF): +def test_functionType_non_existent(PGF): with pytest.raises(KeyError): assert PGF.functionType("cbx")