+++ /dev/null
-from glob import glob
-import os
-import sys
-import termios
-import atexit
-
-BASE_DIR = os.path.dirname(os.path.abspath(__file__))
-
-
-def enable_echo(fd, enabled):
- (iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(fd)
- if enabled:
- lflag |= termios.ECHO
- else:
- lflag &= ~termios.ECHO
- new_attr = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
- termios.tcsetattr(fd, termios.TCSANOW, new_attr)
-
-atexit.register(enable_echo, sys.stdin.fileno(), True)
-
-output = []
-
-
-def log(append=False, *s):
- if append:
- output[-1] += ' ' + ' '.join(str(part) for part in s)
- else:
- output.append(' '.join(str(part) for part in s))
-
-
-def reset_terminal():
- sys.stdout.write('\x1bc\x1b[H')
- sys.stdout.flush()
-
-
-def test():
- count = 0
- passed = 0
- for i, testfile in enumerate(sorted(glob(os.path.join(BASE_DIR, '*.in')))):
- count += 1
- log(False, os.path.basename(testfile))
- reset_terminal()
- with open(testfile) as test:
- sys.stdout.write('\x1b]0;%s\x07' % os.path.basename(testfile))
- sys.stdout.write(test.read()+'\x1bt')
- sys.stdout.flush()
- with open(os.path.join(os.path.dirname(testfile),
- os.path.basename(testfile).split('.')[0]+'.text')) as expected:
- terminal_output = sys.stdin.read()
- if not terminal_output:
- # we are in xterm
- continue
- if terminal_output != expected.read():
- log(True, '\x1b[31merror\x1b[0m')
- with open(os.path.join(os.path.dirname(testfile), 'output',
- os.path.basename(testfile)), 'w') as t_out:
- t_out.write(terminal_output)
- else:
- passed += 1
- log(True, '\x1b[32mpass\x1b[0m')
- return count, passed
-
-
-if __name__ == '__main__':
- enable_echo(sys.stdin.fileno(), False)
- count, passed = test()
- enable_echo(sys.stdin.fileno(), True)
- reset_terminal()
- for i in range(len(output)/2+1):
- if not (i+1) % 25:
- sys.stdin.read()
- print ''.join(i.ljust(40) for i in output[i*2:i*2+2])
- print '\x1b[33mcoverage: %s/%s (%d%%) tests passed.\x1b[0m' % (passed, count, passed*100/count)
var COLS = 80;
var ROWS = 25;
-// primitive pty pipe is enough for the test cases
+/** some helpers for pty interaction */
+// we need a pty in between to get the termios decorations
+// for the basic test cases a raw pty device is enough
var primitive_pty = pty.native.open(COLS, ROWS);
// fake sychronous pty write - read
+// we just pipe the data from slave to master as a child program would do
// pty.js opens pipe fds with O_NONBLOCK
// just wait 10ms instead of setting fds to blocking mode
-function pty_write_read(t, s) {
- fs.writeSync(t.slave, s);
- sleep.usleep(10000);
- var b = Buffer(64000);
- var bytes = fs.readSync(t.master, b, 0, 64000);
- return b.toString('utf8', 0, bytes);
+function pty_write_read(s) {
+ fs.writeSync(primitive_pty.slave, s);
+ sleep.usleep(10000);
+ var b = Buffer(64000);
+ var bytes = fs.readSync(primitive_pty.master, b, 0, 64000);
+ return b.toString('utf8', 0, bytes);
}
-// generate noisy output to compare xterm and emulator
+// make sure raw pty is at x=0 and has no pending data
+function pty_reset() {
+ pty_write_read('\r\n');
+}
+
+/* debug helpers */
+// generate colorful noisy output to compare xterm and emulator cell states
function formatError(in_, out_, expected) {
- function addLineNumber(start, color) {
- var counter = start || 0;
- return function(s) {
- counter += 1;
- return '\x1b[33m' + (' ' + counter).slice(-2) + color + s;
- }
+ function addLineNumber(start, color) {
+ var counter = start || 0;
+ return function(s) {
+ counter += 1;
+ return '\x1b[33m' + (' ' + counter).slice(-2) + color + s;
}
- var line80 = '12345678901234567890123456789012345678901234567890123456789012345678901234567890';
- var s = '';
- s += '\n\x1b[34m' + JSON.stringify(in_);
- s += '\n\x1b[33m ' + line80 + '\n';
- s += out_.split('\n').map(addLineNumber(0, '\x1b[31m')).join('\n');
- s += '\n\x1b[33m ' + line80 + '\n';
- s += expected.split('\n').map(addLineNumber(0, '\x1b[32m')).join('\n');
- return s;
+ }
+ var line80 = '12345678901234567890123456789012345678901234567890123456789012345678901234567890';
+ var s = '';
+ s += '\n\x1b[34m' + JSON.stringify(in_);
+ s += '\n\x1b[33m ' + line80 + '\n';
+ s += out_.split('\n').map(addLineNumber(0, '\x1b[31m')).join('\n');
+ s += '\n\x1b[33m ' + line80 + '\n';
+ s += expected.split('\n').map(addLineNumber(0, '\x1b[32m')).join('\n');
+ return s;
}
// simple debug output of terminal cells
function terminalToString(term) {
- var result = '';
- var line_s = '';
- for (var line=0; line<term.rows; ++line) {
- line_s = '';
- for (var cell=0; cell<term.cols; ++cell) {
- line_s += term.lines[line][cell][1];
- }
- // rtrim empty cells as xterm does
- line_s = line_s.replace(/\s+$/, '');
- result += line_s;
- result += '\n';
+ var result = '';
+ var line_s = '';
+ for (var line=0; line<term.rows; ++line) {
+ line_s = '';
+ for (var cell=0; cell<term.cols; ++cell) {
+ line_s += term.lines[line][cell][1];
}
- return result;
+ // rtrim empty cells as xterm does
+ line_s = line_s.replace(/\s+$/, '');
+ result += line_s;
+ result += '\n';
+ }
+ return result;
}
-describe('Escape code files', function() {
- var xterm;
+/** tests */
+describe('xterm output comparison', function() {
+ var xterm;
- beforeEach(function () {
- xterm = new Terminal(80, 25);
- });
+ beforeEach(function () {
+ xterm = new Terminal(COLS, ROWS);
+ xterm.refresh = function() {};
+ });
- // omit stack trace for escape sequence files
- Error.stackTraceLimit = 0;
- var files = glob.sync('test/escape_sequence_files/*.in');
- // comment/uncomment one of the following
- // only sucessful tests
- var successful = [0, 2, 6, 12, 13, 18, 20, 22, 27, 28];
- for (var a in successful) {
- var i = successful[a];
- // first 44 are the most basic escape sequences
- //for (var i=0; i<44; ++i) {
- // all tests
- //for (var i=0; i<files.length; ++i) {
- (function(filename){
- it(filename.split('/').slice(-1)[0], function () {
- var in_file = fs.readFileSync(filename, 'utf8');
- var from_pty = pty_write_read(primitive_pty, in_file);
- // uncomment this to get log from terminal
- console.log = function(){};
- xterm.write(from_pty);
- var from_emulator = terminalToString(xterm);
- console.log = CONSOLE_LOG;
- var expected = fs.readFileSync(filename.split('.')[0] + '.text', 'utf8');
- if (from_emulator != expected) {
- // uncomment to get noisy output
- //throw new Error(formatError(in_file, from_emulator, expected));
- throw new Error('mismatch');
- }
- });
- })(files[i]);
- }
+ // omit stack trace for escape sequence files
+ Error.stackTraceLimit = 0;
+ var files = glob.sync('test/escape_sequence_files/*.in');
+ // only successful tests for now
+ var successful = [0, 2, 6, 12, 13, 18, 20, 22, 27, 28];
+ for (var a in successful) {
+ var i = successful[a];
+ (function(filename){
+ it(filename.split('/').slice(-1)[0], function () {
+ pty_reset();
+ var in_file = fs.readFileSync(filename, 'utf8');
+ var from_pty = pty_write_read(in_file);
+ // uncomment this to get log from terminal
+ console.log = function(){};
+ xterm.write(from_pty);
+ var from_emulator = terminalToString(xterm);
+ console.log = CONSOLE_LOG;
+ var expected = fs.readFileSync(filename.split('.')[0] + '.text', 'utf8');
+ if (from_emulator != expected) {
+ // uncomment to get noisy output
+ //throw new Error(formatError(in_file, from_emulator, expected));
+ throw new Error('mismatch');
+ }
+ });
+ })(files[i]);
+ }
});