return if global.testingBrowser os = require 'os' fs = require 'fs' path = require 'path' # REPL # ---- Stream = require 'stream' class MockInputStream extends Stream constructor: -> super() @readable = true resume: -> emitLine: (val) -> @emit 'data', Buffer.from("#{val}\n") class MockOutputStream extends Stream constructor: -> super() @writable = true @written = [] write: (data) -> # console.log 'output write', arguments @written.push data lastWrite: (fromEnd = -1) -> @written[@written.length - 1 + fromEnd].replace /\r?\n$/, '' # Create a dummy history file historyFile = path.join os.tmpdir(), '.coffee_history_test' fs.writeFileSync historyFile, '1 + 2\n' testRepl = (desc, fn) -> input = new MockInputStream output = new MockOutputStream repl = Repl.start {input, output, historyFile} test desc, -> fn input, output, repl ctrlV = { ctrl: true, name: 'v'} testRepl 'reads history file', (input, output, repl) -> input.emitLine repl.history[0] eq '3', output.lastWrite() testRepl "starts with coffee prompt", (input, output) -> eq 'coffee> ', output.lastWrite(0) testRepl "writes eval to output", (input, output) -> input.emitLine '1+1' eq '2', output.lastWrite() testRepl "comments are ignored", (input, output) -> input.emitLine '1 + 1 #foo' eq '2', output.lastWrite() testRepl "output in inspect mode", (input, output) -> input.emitLine '"1 + 1\\n"' eq "'1 + 1\\n'", output.lastWrite() testRepl "variables are saved", (input, output) -> input.emitLine "foo = 'foo'" input.emitLine 'foobar = "#{foo}bar"' eq "'foobar'", output.lastWrite() testRepl "empty command evaluates to undefined", (input, output) -> # A regression fixed in Node 5.11.0 broke the handling of pressing enter in # the Node REPL; see https://github.com/nodejs/node/pull/6090 and # https://github.com/jashkenas/coffeescript/issues/4502. # Just skip this test for versions of Node < 6. return if parseInt(process.versions.node.split('.')[0], 10) < 6 input.emitLine '' eq 'undefined', output.lastWrite() testRepl "#4763: comment evaluates to undefined", (input, output) -> input.emitLine '# comment' eq 'undefined', output.lastWrite() testRepl "#4763: multiple comments evaluate to undefined", (input, output) -> input.emitLine '### a ### ### b ### # c' eq 'undefined', output.lastWrite() testRepl "ctrl-v toggles multiline prompt", (input, output) -> input.emit 'keypress', null, ctrlV eq '------> ', output.lastWrite(0) input.emit 'keypress', null, ctrlV eq 'coffee> ', output.lastWrite(0) testRepl "multiline continuation changes prompt", (input, output) -> input.emit 'keypress', null, ctrlV input.emitLine '' eq '....... ', output.lastWrite(0) testRepl "evaluates multiline", (input, output) -> # Stubs. Could assert on their use. output.cursorTo = (pos) -> output.clearLine = -> input.emit 'keypress', null, ctrlV input.emitLine 'do ->' input.emitLine ' 1 + 1' input.emit 'keypress', null, ctrlV eq '2', output.lastWrite() testRepl "variables in scope are preserved", (input, output) -> input.emitLine 'a = 1' input.emitLine 'do -> a = 2' input.emitLine 'a' eq '2', output.lastWrite() testRepl "existential assignment of previously declared variable", (input, output) -> input.emitLine 'a = null' input.emitLine 'a ?= 42' eq '42', output.lastWrite() testRepl "keeps running after runtime error", (input, output) -> input.emitLine 'a = b' input.emitLine 'a' eq 'undefined', output.lastWrite() testRepl "#4604: wraps an async function", (input, output) -> return unless try new Function 'async () => {}' # Feature detect support for async functions. input.emitLine 'await new Promise (resolve) -> setTimeout (-> resolve 33), 10' setTimeout -> eq '33', output.lastWrite() , 20 testRepl "transpile REPL", (input, output) -> input.emitLine 'require("./test/importing/transpile_import").getSep()' eq "'#{path.sep.replace '\\', '\\\\'}'", output.lastWrite() process.on 'exit', -> try fs.unlinkSync historyFile catch exception # Already deleted, nothing else to do.