import * as fs from 'fs' ; import { flatten , includes } from 'lodash' ; import * as path from 'path' ; import { bindNodeCallback } from 'rxjs' ; import { map } from 'rxjs/operators' ; import { HunspellFactory } from '../../src/HunspellFactory' ; import { loadModule } from '../../src/loadModule' ; import { excludedWords } from '../util' ; const readFile = bindNodeCallback ( fs . readFile ) ; const mountBufferHunspell = async ( factory , dirPath , fixture ) => { const buffers = [ ] ; const read = async ( filePath ) => { const mountedPath = factory . mountBuffer ( ( await readFile ( filePath ) . toPromise ( ) ) ! ) ; buffers . push ( mountedPath ) ; return mountedPath ; } ; const aff = await read ( path . join ( `${ dirPath }` , `${ fixture }.aff` ) ) ; const dic = await read ( path . join ( `${ dirPath }` , `${ fixture }.dic` ) ) ; const hunspell = factory . create ( aff , dic ) ; return { read , hunspell , dispose : ( ) => { hunspell . dispose ( ) ; buffers . forEach ( ( x ) => factory . unmount ( x ) ) ; } , } ; } ; /**
 * Location to fixture files
 */ const baseFixturePath = path . join ( __dirname , '../__fixtures__' ) ; enum TestType { MatchSpell = '.good' , MismatchSpell = '.wrong' , Suggestion = '.sug' , Stem = '.stem' } enum MountType { Buffer = 'buffer' } param fixturePath param testType const getFixtureList = ( fixturePath , testType , skipList = [ ] ) => flatten ( fs . readdirSync ( fixturePath ) . filter ( ( file ) => path . extname ( file ) === testType ) . map ( ( file ) => path . basename ( file , testType ) ) . filter ( ( x ) => { if ( includes ( skipList , x ) ) { console . log ( `Skipping test fixture '${ x }'` ) ; return false ; } return true ; } ) . map < Array < [ string , MountType , ( factory : HunspellFactory ) => ReturnType < typeof mountBufferHunspell > ] > > ( ( fixture ) => [ [ fixture , MountType . Buffer , async ( factory ) => await mountBufferHunspell ( factory , baseFixturePath , fixture ) ] , ] ) ) ; const readWords = async ( fixture , testType ) : Promise < Array < string > > => await ( readFile as any ) ( `${ path . join ( baseFixturePath , fixture ) }${ testType }` , 'utf-8' ) . pipe ( map ( ( value ) => value . split ( '\n' ) . filter ( ( x ) => ! ! x ) ) ) . toPromise ( ) ; const getExpectedWords = ( expectedWordsFileName ) : Array < string | string [ ] | null > => { return ( [ ... fs . readFileSync ( expectedWordsFileName , 'utf-8' ) . split ( '\n' ) . filter ( ( x ) => ! ! x ) . map ( ( x ) => { const splitted = x . split ( ', ' ) ; if ( splitted . length === 1 && ! includes ( excludedWords , splitted [ 0 ] ) ) { return splitted [ 0 ] ; } const filtered = splitted . filter ( ( word ) => ! includes ( excludedWords , word ) ) ; if ( filtered . length > 0 ) { return filtered ; } return null ; } ) , ] || [ ] ) . filter ( ( x ) => ! ! x ) ; } ; /**
 * running original hunspell's spec.
 *
 */ describe ( 'hunspell' , ( ) => { let hunspellFactory ; beforeAll ( async ( ) => { hunspellFactory = await loadModule ( ) ; } ) ; param fixture param testType param assertionValue param expected const buildSpellAssertion = ( testType , expectedValue , skipList = [ ] ) => { const fixtureList = getFixtureList ( baseFixturePath , testType , skipList ) ; it . each ( fixtureList ) ( `fixture '%s' for %s` , async ( fixture , _mountType , factory ) => { const { hunspell , dispose } = await factory ( hunspellFactory ) ; const words = await readWords ( fixture , testType ) ; words . filter ( ( word ) => ! includes ( excludedWords , word ) ) . forEach ( ( word ) => { const value = hunspell . spell ( word ) ; expect ( { word , value } ) . toEqual ( { word , value : expectedValue } ) ; } ) ; dispose ( ) ; } ) ; } ; describe ( 'should match correct word' , ( ) => { const matchCorrectWordFixtureSkipList = [ 'morph' ] ; buildSpellAssertion ( TestType . MatchSpell , true , matchCorrectWordFixtureSkipList ) ; } ) ; describe ( 'should match missplled word' , ( ) => { buildSpellAssertion ( TestType . MismatchSpell , false ) ; } ) ; describe ( 'should suggest misspelled word-refactor' , ( ) => { const testType = TestType . Suggestion ; const suggestionFixtureSkipList = [ '1463589' , 'i54633' , 'map' ] ; const fixtureList = getFixtureList ( baseFixturePath , TestType . Suggestion , suggestionFixtureSkipList ) ; it . each ( fixtureList ) ( `fixture '%s' for %s` , async ( fixture , _mountType , factory ) => { const { hunspell , dispose } = await factory ( hunspellFactory ) ; const base = path . join ( baseFixturePath , `${ fixture }` ) ; const expectedSuggestions = getExpectedWords ( `${ base }${ testType }` ) ; const words = await readWords ( fixture , TestType . MismatchSpell ) ; const suggested = [ ] ; words . filter ( ( word ) => ! includes ( excludedWords , word ) ) . forEach ( ( word ) => { const ret = hunspell . suggest ( word ) ; if ( ret . length > 0 ) { suggested . push ( ret . length > 1 ? ret : ret [ 0 ] ) ; } } ) ; expect ( suggested ) . toEqual ( expectedSuggestions ) ; dispose ( ) ; } ) ; } ) ; describe ( 'should suggest stems' , ( ) => { const testType = TestType . Stem ; const fixtureList = getFixtureList ( baseFixturePath , testType , [ ] ) ; it . each ( fixtureList ) ( `fixture '%s' for %s` , async ( fixture , _mountType , factory ) => { const { hunspell , dispose } = await factory ( hunspellFactory ) ; const base = path . join ( baseFixturePath , `${ fixture }` ) ; const expectedStems = getExpectedWords ( `${ base }${ testType }` ) ; const words = await readWords ( fixture , TestType . MatchSpell ) ; const stemmed = [ ] ; words . filter ( ( word ) => ! includes ( excludedWords , word ) ) . forEach ( ( word ) => { const ret = hunspell . stem ( word ) ; if ( ret . length > 0 ) { stemmed . push ( ret . length > 1 ? ret : ret [ 0 ] ) ; } } ) ; expect ( stemmed ) . toEqual ( expectedStems ) ; dispose ( ) ; } ) ; } ) ; describe ( 'add words or dictionary in runtime' , ( ) => { const getHunspell = ( ) => mountBufferHunspell ( hunspellFactory , baseFixturePath , 'base' ) ; it . each ( [ MountType . Buffer ] ) ( 'should able to add new dictionary into existing dictionary for %s' , async ( ) => { const { hunspell , dispose , read } = await getHunspell ( ) ; expect ( hunspell . spell ( 'foo' ) ) . toBe ( false ) ; hunspell . addDictionary ( await read ( path . join ( baseFixturePath , 'break.dic' ) ) ) ; expect ( hunspell . spell ( 'foo' ) ) . toBe ( true ) ; dispose ( ) ; } ) ; it . each ( [ MountType . Buffer ] ) ( 'should able to add new word into existing dictionary for %s' , async ( ) => { const { hunspell , dispose } = await getHunspell ( ) ; expect ( hunspell . spell ( 'nonexistword' ) ) . toBe ( false ) ; hunspell . addWord ( 'nonexistword' ) ; expect ( hunspell . spell ( 'nonexistword' ) ) . toBe ( true ) ; dispose ( ) ; } ) ; it . each ( [ MountType . Buffer ] ) ( 'should able to add new word with affix into existing dictionary for %s' , async ( ) => { const { hunspell , dispose } = await getHunspell ( ) ; expect ( hunspell . spell ( 'tre' ) ) . toBe ( false ) ; hunspell . addWordWithAffix ( 'tre' , 'uncreate' ) ; expect ( hunspell . spell ( 'tre' ) ) . toBe ( true ) ; expect ( hunspell . spell ( 'trive' ) ) . toBe ( true ) ; dispose ( ) ; } ) ; it . each ( [ MountType . Buffer ] ) ( 'should able to remove word from existing dictionary for %s' , async ( ) => { const { hunspell , dispose } = await getHunspell ( ) ; expect ( hunspell . spell ( 'seven' ) ) . toBe ( true ) ; hunspell . removeWord ( 'seven' ) ; expect ( hunspell . spell ( 'seven' ) ) . toBe ( false ) ; dispose ( ) ; } ) ; } ) ; } ) ;