diff --git a/packages/rrreol-core/src/judge.js b/packages/rrreol-core/src/judge.js index 6c9b72a..5097a0b 100644 --- a/packages/rrreol-core/src/judge.js +++ b/packages/rrreol-core/src/judge.js @@ -17,7 +17,8 @@ export class Judge extends EventEmitter { const { input = [], output = [], - file = isString(props) ? props : null + file = isString(props) ? props : null, + ignoreEndEnter = true } = props this.__outputs = output.map((val) => { @@ -27,6 +28,13 @@ export class Judge extends EventEmitter { return new FileManager(val) }) this.__answer = [] + this.__config = Object.assign({ + ignoreEndEnter: true // if ignore the `\n` at the line end + }, { + ignoreEndEnter + }) + + this.__task = [] this.__path = file || null this.__target = 0 @@ -34,6 +42,7 @@ export class Judge extends EventEmitter { this.on('start', this.exec) this.on('finished', () => { // todo + console.log(chalk.greenBright('finished')) }) } @@ -83,9 +92,10 @@ export class Judge extends EventEmitter { if (isNil(this.__outputs[this.__target])) { console.log(chalk.red('error') + 'target file is empty') } else if (isString(val)) { + // todo findIndex(propEq('name', val))(this.__outputs) } - this.__target = val + this.__target = val - 1 return this } @@ -105,16 +115,67 @@ export class Judge extends EventEmitter { const path = await Compiler.compile(this.__path, outputPath) console.log(`${chalk.yellowBright('Compiled')} file`) const runner = new Runner(path) + + let index = 0 for await (const input of this.__inputs) { const res = await runner.execUnsafe(input) - const fm = FileManager.of().loadContent(res) - this.__answer.push(fm) - this.emit('finished', fm) + const fileManager = FileManager.of().loadContent(res) + this.__answer.push(fileManager) + // check output + const success = this.compareFileManager(fileManager, this.out(index + 1)) + if (!success) { + console.log(`${chalk.red('error on file')} ${index + 1}`) + } + + ++index } return this } + compareFileManager = (realFM, expectedFM) => { + if (!(realFM instanceof FileManager) || + !(expectedFM instanceof FileManager)) { + throw new TypeError() + } + let success = true + Object.keys(Array(realFM.lines())).forEach((_, line) => { + const realLine = realFM.line(++line) + const expectedLine = expectedFM.line(line) + const same = equals(realLine, expectedLine) + if (!same) { + success = false + // todo: support log column + console.log(`${chalk.red('wrong answer: On line')} ${line}, read ${realLine} expected ${expectedLine}`) + } + }) + return success + } + run = () => this.emit('start') + + line = (line) => { + return JudgeWrapper.of.call(this, curry((val) => { + return equals(this.targetFile.line(line), val) + })) + } + + lines = () => { + return JudgeWrapper.of.call(this, curry((val) => { + return this.targetFile.lines() === val + })) + } + + maxline = () => { + return JudgeWrapper.of.call(this, curry((val) => { + return this.targetFile.lines() <= val + })) + } + + minline = () => { + return JudgeWrapper.of.call(this, curry((val) => { + return this.targetFile.lines() >= val + })) + } } export default Judge diff --git a/packages/rrreol-core/src/judgeWrapper.js b/packages/rrreol-core/src/judgeWrapper.js index f193f36..77dc1f0 100644 --- a/packages/rrreol-core/src/judgeWrapper.js +++ b/packages/rrreol-core/src/judgeWrapper.js @@ -8,19 +8,17 @@ export class JudgeWrapper { return new JudgeWrapper(val, this) } - constructor (val, target) { - if (isNil(val)) { + constructor (fn, target) { + if (isNil(fn)) { throw TypeError('val is null') } this.__target = target || null - this.__val = val + this.__fn = fn } toBe = (val) => { if ('on' in this.__target) { - this.__target.on('finished', (answer) => { - - }) + this.__target.on('finished', () => this.__fn(val)) } else { throw new Error('no property \'on\'') } diff --git a/packages/rrreol-core/test/unit/judge.test.js b/packages/rrreol-core/test/unit/judge.test.js index 95879aa..9d2d021 100644 --- a/packages/rrreol-core/test/unit/judge.test.js +++ b/packages/rrreol-core/test/unit/judge.test.js @@ -10,6 +10,10 @@ describe('Judge base test', () => { judge = new Judge() }) + it('should have correct props', () => { + expect(judge.__config.ignoreEndEnter).toBe(true) + }) + it('should throw error when invoke get method', () => { expect(() => { judge.targetFile = 1 @@ -64,7 +68,42 @@ describe('Judge check test', () => { expect(judge.answer(1).content).toEqual('1 2') }) + it('should emit check running success', () => { + const fm1 = FileManager.of().loadContent('1\n2\n') + const fm2 = FileManager.of().loadContent('1\n2\n') + judge.rawListeners('check') + .map(f => f(fm1, fm2)) + .every(v => expect(v).toBeTruthy()) + }) + afterAll(() => { removeFiles(fixturesPath, /\.test\.out$/) }) }) + +describe('Judge check park', () => { + let judge = null + beforeEach(() => { + judge = new Judge() + }) + + it('should get the correct line content', () => { + judge.in(1).loadContent('1\n2\n3') + judge.out(1).loadContent('4\n5\n6') + judge.line(1).toBe('1') + judge.line(2).toBe('2') + judge.line(3).toBe('3') + // judge.exec() + judge.emit('finished') + }) + + it('should get the correct max/min line content', () => { + judge.in(1).loadContent('1\n2\n3') + judge.out(1).loadContent('4\n5\n6') + judge.lines().toBe(3) + judge.maxline().toBe(4) + judge.minline().toBe(1) + // judge.exec() + judge.emit('finished') + }) +})