scriptty 0.5.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +3 -0
  3. data/COPYING +674 -0
  4. data/COPYING.LESSER +165 -0
  5. data/README.rdoc +31 -0
  6. data/Rakefile +49 -0
  7. data/VERSION +1 -0
  8. data/bin/scriptty-capture +5 -0
  9. data/bin/scriptty-dump-screens +4 -0
  10. data/bin/scriptty-replay +5 -0
  11. data/bin/scriptty-term-test +4 -0
  12. data/bin/scriptty-transcript-parse +4 -0
  13. data/examples/captures/xterm-overlong-line-prompt.bin +9 -0
  14. data/examples/captures/xterm-vim-session.bin +262 -0
  15. data/examples/demo-capture.rb +19 -0
  16. data/examples/telnet-nego.rb +55 -0
  17. data/lib/scriptty/apps/capture_app/console.rb +104 -0
  18. data/lib/scriptty/apps/capture_app/password_prompt.rb +65 -0
  19. data/lib/scriptty/apps/capture_app.rb +213 -0
  20. data/lib/scriptty/apps/dump_screens_app.rb +166 -0
  21. data/lib/scriptty/apps/replay_app.rb +229 -0
  22. data/lib/scriptty/apps/term_test_app.rb +124 -0
  23. data/lib/scriptty/apps/transcript_parse_app.rb +143 -0
  24. data/lib/scriptty/cursor.rb +39 -0
  25. data/lib/scriptty/exception.rb +38 -0
  26. data/lib/scriptty/expect.rb +392 -0
  27. data/lib/scriptty/multiline_buffer.rb +192 -0
  28. data/lib/scriptty/net/event_loop.rb +610 -0
  29. data/lib/scriptty/screen_pattern/generator.rb +398 -0
  30. data/lib/scriptty/screen_pattern/parser.rb +558 -0
  31. data/lib/scriptty/screen_pattern.rb +104 -0
  32. data/lib/scriptty/term/dg410/dg410-client-escapes.txt +37 -0
  33. data/lib/scriptty/term/dg410/dg410-escapes.txt +82 -0
  34. data/lib/scriptty/term/dg410/parser.rb +162 -0
  35. data/lib/scriptty/term/dg410.rb +489 -0
  36. data/lib/scriptty/term/xterm/xterm-escapes.txt +73 -0
  37. data/lib/scriptty/term/xterm.rb +661 -0
  38. data/lib/scriptty/term.rb +40 -0
  39. data/lib/scriptty/util/fsm/definition_parser.rb +111 -0
  40. data/lib/scriptty/util/fsm/scriptty_fsm_definition.treetop +189 -0
  41. data/lib/scriptty/util/fsm.rb +177 -0
  42. data/lib/scriptty/util/transcript/reader.rb +96 -0
  43. data/lib/scriptty/util/transcript/writer.rb +111 -0
  44. data/test/apps/capture_app_test.rb +123 -0
  45. data/test/apps/transcript_parse_app_test.rb +118 -0
  46. data/test/cursor_test.rb +51 -0
  47. data/test/fsm_definition_parser_test.rb +220 -0
  48. data/test/fsm_test.rb +322 -0
  49. data/test/multiline_buffer_test.rb +275 -0
  50. data/test/net/event_loop_test.rb +402 -0
  51. data/test/screen_pattern/generator_test.rb +408 -0
  52. data/test/screen_pattern/parser_test/explicit_cursor_pattern.txt +14 -0
  53. data/test/screen_pattern/parser_test/explicit_fields.txt +22 -0
  54. data/test/screen_pattern/parser_test/multiple_patterns.txt +42 -0
  55. data/test/screen_pattern/parser_test/simple_pattern.txt +14 -0
  56. data/test/screen_pattern/parser_test/truncated_heredoc.txt +12 -0
  57. data/test/screen_pattern/parser_test/utf16bebom_pattern.bin +0 -0
  58. data/test/screen_pattern/parser_test/utf16lebom_pattern.bin +0 -0
  59. data/test/screen_pattern/parser_test/utf8_pattern.bin +14 -0
  60. data/test/screen_pattern/parser_test/utf8_unix_pattern.bin +14 -0
  61. data/test/screen_pattern/parser_test/utf8bom_pattern.bin +14 -0
  62. data/test/screen_pattern/parser_test.rb +266 -0
  63. data/test/term/dg410/parser_test.rb +139 -0
  64. data/test/term/xterm_test.rb +327 -0
  65. data/test/test_helper.rb +3 -0
  66. data/test/util/transcript/reader_test.rb +131 -0
  67. data/test/util/transcript/writer_test.rb +126 -0
  68. data/test.watchr +29 -0
  69. metadata +175 -0
@@ -0,0 +1,327 @@
1
+ # = Tests for ScripTTY::Term::XTerm
2
+ # Copyright (C) 2010 Infonium Inc.
3
+ #
4
+ # This file is part of ScripTTY.
5
+ #
6
+ # ScripTTY is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # ScripTTY is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require File.dirname(__FILE__) + "/../test_helper.rb"
20
+ require 'scriptty/term/xterm'
21
+
22
+ class XtermTest < Test::Unit::TestCase
23
+
24
+ def test_initial_cursor_position
25
+ s = ScripTTY::Term::XTerm.new(5, 10)
26
+ assert_equal [0,0], s.cursor_pos
27
+ end
28
+
29
+ def test_width_height
30
+ s = ScripTTY::Term::XTerm.new(5, 10)
31
+ assert_equal 10, s.width
32
+ assert_equal 5, s.height
33
+ end
34
+
35
+ def test_unknown_sequence_raises_nomatch_by_default
36
+ before = [ "aaaaaaaaaa",
37
+ "bbbbbbbbbb",
38
+ "cccccccccc",
39
+ "dddddddddd",
40
+ "eeeeeeeeee" ]
41
+
42
+ after = [ "FOOaaaaaaa",
43
+ "bbbbbbbbbb",
44
+ "cccccccccc",
45
+ "dddddddddd",
46
+ "eeeeeeeeee" ]
47
+
48
+ screen_modify_test(before, after) do |s|
49
+ assert_raise ScripTTY::Util::FSM::NoMatch do
50
+ s.feed_bytes("\e[\e") # bogus escape sequence ESC [ ESC
51
+ end
52
+ s.feed_bytes("FOO")
53
+ end
54
+ end
55
+
56
+ def test_unknown_sequence_ignore
57
+ before = [ "aaaaaaaaaa",
58
+ "bbbbbbbbbb",
59
+ "cccccccccc",
60
+ "dddddddddd",
61
+ "eeeeeeeeee" ]
62
+
63
+ after = [ "FOOaaaaaaa",
64
+ "bbbbbbbbbb",
65
+ "cccccccccc",
66
+ "dddddddddd",
67
+ "eeeeeeeeee" ]
68
+
69
+ screen_modify_test(before, after) do |s|
70
+ s.on_unknown_sequence :ignore
71
+ s.feed_bytes("\e[\eFOO") # bogus escape sequence ESC [ ESC
72
+ end
73
+ end
74
+
75
+ def test_unknown_sequence_proc
76
+ before = [ "aaaaaaaaaa",
77
+ "bbbbbbbbbb",
78
+ "cccccccccc",
79
+ "dddddddddd",
80
+ "eeeeeeeeee" ]
81
+
82
+ after = [ "[BOGO]FOOa",
83
+ "bbbbbbbbbb",
84
+ "cccccccccc",
85
+ "dddddddddd",
86
+ "eeeeeeeeee" ]
87
+
88
+ screen_modify_test(before, after) do |s|
89
+ s.on_unknown_sequence do |seq|
90
+ assert_equal "\e[\e", seq
91
+ s.feed_bytes "[BOGO]" # the state machine should already be reset, so we should be able to feed alternative bytes here.
92
+ end
93
+ s.feed_bytes("\e[\eFOO") # bogus escape sequence ESC [ ESC
94
+ end
95
+ end
96
+
97
+ def test_cursor_position
98
+ s = ScripTTY::Term::XTerm.new(5, 10)
99
+
100
+ s.cursor_pos = [4,8]
101
+ s.feed_bytes("\e[H")
102
+ assert_equal [0,0], s.cursor_pos
103
+
104
+ s.cursor_pos = [4,8]
105
+ s.feed_bytes("\e[4H")
106
+ assert_equal [3,0], s.cursor_pos
107
+
108
+ s.cursor_pos = [4,8]
109
+ s.feed_bytes("\e[;4H")
110
+ assert_equal [0,3], s.cursor_pos
111
+
112
+ s.cursor_pos = [4,8]
113
+ s.feed_bytes("\e[0;0H")
114
+ assert_equal [0,0], s.cursor_pos
115
+
116
+ s.cursor_pos = [4,8]
117
+ s.feed_bytes("\e[1;1H")
118
+ assert_equal [0,0], s.cursor_pos
119
+
120
+ s.cursor_pos = [4,8]
121
+ s.feed_bytes("\e[4;5H")
122
+ assert_equal [3,4], s.cursor_pos
123
+ end
124
+
125
+ def test_cursor_up
126
+ {"" => 1, "0" => 1, "1" => 1, "2" => 2, "3" => 3}.each_pair do |p,n|
127
+ s = ScripTTY::Term::XTerm.new(5, 10)
128
+ col = 1
129
+ (n..s.height-1).to_a.reverse.each do |row|
130
+ s.cursor_pos = [row,col]
131
+ s.feed_bytes("\e[#{p}A")
132
+ assert_equal [row-n,col], s.cursor_pos, "should move cursor from row #{row} to row #{row-n}"
133
+ end
134
+
135
+ assert_equal [0,col], s.cursor_pos, "sanity check"
136
+ s.feed_bytes("\e[#{p}A")
137
+ assert_equal [0,col], s.cursor_pos, "cursor should not move past screen edge"
138
+ end
139
+ end
140
+
141
+ def test_cursor_down
142
+ {"" => 1, "0" => 1, "1" => 1, "2" => 2, "3" => 3}.each_pair do |p,n|
143
+ s = ScripTTY::Term::XTerm.new(5, 10)
144
+ col = 1
145
+ (0..s.height-1-n).each do |row|
146
+ s.cursor_pos = [row,col]
147
+ s.feed_bytes("\e[#{p}B")
148
+ assert_equal [row+n,col], s.cursor_pos, "ESC[#{p}B should move cursor from row #{row} to row #{row+n}"
149
+ end
150
+
151
+ assert_equal [s.height-1,col], s.cursor_pos, "sanity check"
152
+ s.feed_bytes("\e[#{p}B")
153
+ assert_equal [s.height-1,col], s.cursor_pos, "cursor should not move past screen edge"
154
+ end
155
+ end
156
+
157
+ def test_cursor_right
158
+ {"" => 1, "0" => 1, "1" => 1, "2" => 2, "3" => 3}.each_pair do |p,n|
159
+ s = ScripTTY::Term::XTerm.new(5, 10)
160
+ row = 1
161
+ (0..s.width-1-n).each do |col|
162
+ s.cursor_pos = [row,col]
163
+ s.feed_bytes("\e[#{p}C")
164
+ assert_equal [row,col+n], s.cursor_pos, "ESC[#{p}C should move cursor from col #{col} to col #{col+n}"
165
+ end
166
+
167
+ assert_equal [row,s.width-1], s.cursor_pos, "sanity check"
168
+ s.feed_bytes("\e[#{p}C")
169
+ assert_equal [row,s.width-1], s.cursor_pos, "cursor should not move past screen edge"
170
+ end
171
+ end
172
+
173
+ def test_cursor_left
174
+ {"" => 1, "0" => 1, "1" => 1, "2" => 2, "3" => 3}.each_pair do |p,n|
175
+ s = ScripTTY::Term::XTerm.new(5, 10)
176
+ row = 1
177
+ (n..s.width-1).to_a.reverse.each do |col|
178
+ s.cursor_pos = [row,col]
179
+ s.feed_bytes("\e[#{p}D")
180
+ assert_equal [row,col-n], s.cursor_pos, "ESC[#{p}D should move cursor from col #{col} to col #{col-n}"
181
+ end
182
+
183
+ assert_equal [row,0], s.cursor_pos, "sanity check"
184
+ s.feed_bytes("\e[#{p}D")
185
+ assert_equal [row,0], s.cursor_pos, "cursor should not move past screen edge"
186
+ end
187
+ end
188
+
189
+ def test_new_line
190
+ s = ScripTTY::Term::XTerm.new(5, 10)
191
+
192
+ s.cursor_pos = [0,4]
193
+ s.feed_bytes("\n\n")
194
+ assert_equal [2,0], s.cursor_pos
195
+ end
196
+
197
+ def test_carriage_return
198
+ s = ScripTTY::Term::XTerm.new(5, 10)
199
+
200
+ s.cursor_pos = [0,4]
201
+ s.feed_bytes("\r\r")
202
+ assert_equal [0,0], s.cursor_pos
203
+ end
204
+
205
+ def test_restore_cursor_never_saved
206
+ s = ScripTTY::Term::XTerm.new(5, 10)
207
+ s.cursor_pos = [2, 4]
208
+ s.feed_bytes("\e[u") # ANSI restore cursor
209
+ assert_equal [0, 0], s.cursor_pos, "ANSI restore cursor should default to home position"
210
+
211
+ s.cursor_pos = [2, 4]
212
+ s.feed_bytes("\e8") # DEC restore cursor
213
+ assert_equal [0, 0], s.cursor_pos, "DEC restore cursor should default to home position"
214
+ end
215
+
216
+ def test_save_cursor_restore_cursor
217
+ s = ScripTTY::Term::XTerm.new(5, 10)
218
+ s.cursor_pos = [2, 4]
219
+ s.feed_bytes("\e[s") # ANSI save cursor
220
+
221
+ s.cursor_pos = [0, 0]
222
+ s.feed_bytes("\e[u") # ANSI restore cursor
223
+ assert_equal [2, 4], s.cursor_pos, "ANSI restore cursor"
224
+
225
+ s.cursor_pos = [1, 3]
226
+ s.feed_bytes("\e7") # DEC save cursor
227
+
228
+ s.cursor_pos = [0, 0]
229
+ s.feed_bytes("\e8") # DEC restore cursor
230
+ assert_equal [1, 3], s.cursor_pos, "DEC restore cursor"
231
+ end
232
+
233
+ def test_scroll_up
234
+ before = [ "aaaaaaaaaa",
235
+ "bbbbbbbbbb",
236
+ "cccccccccc",
237
+ "dddddddddd",
238
+ "eeeeeeeeee" ]
239
+
240
+ after = [ "bbbbbbbbbb",
241
+ "cccccccccc",
242
+ "dddddddddd",
243
+ "eeeeeeeeee",
244
+ " " ]
245
+
246
+ screen_modify_test(before, after, "scroll up on newline") do |s|
247
+ s.cursor_pos = [4,0]
248
+ s.feed_bytes("\n")
249
+ end
250
+ end
251
+
252
+
253
+ def test_scroll_up_with_scrolling_region
254
+ before = [ "aaaaaaaaaa",
255
+ "bbbbbbbbbb",
256
+ "cccccccccc",
257
+ "dddddddddd",
258
+ "eeeeeeeeee" ]
259
+
260
+ after = [ "aaaaaaaaaa",
261
+ "cccccccccc",
262
+ "dddddddddd",
263
+ " ",
264
+ "eeeeeeeeee" ]
265
+
266
+ screen_modify_test(before, after) do |s|
267
+ s.cursor_pos = [3,0]
268
+ s.feed_bytes("\e[2;4r") # set scrolling region
269
+ s.feed_bytes("\n")
270
+ end
271
+ end
272
+
273
+ def test_printable
274
+ before = [" "*10]*5
275
+ after = [ "Hello! ",
276
+ " ",
277
+ " ",
278
+ " ",
279
+ " " ]
280
+
281
+ screen_modify_test(before, after) do |s|
282
+ s.feed_bytes("Hello!")
283
+ assert_equal [0,6], s.cursor_pos
284
+ end
285
+ end
286
+
287
+ def test_carriage_return
288
+ before = [" "*10]*5
289
+ after = [ "world! ",
290
+ " ",
291
+ " ",
292
+ " ",
293
+ " " ]
294
+
295
+ screen_modify_test(before, after) do |s|
296
+ s.feed_bytes("hello!\rworld")
297
+ end
298
+ end
299
+
300
+ # Test line_feed (no wrapping)
301
+ def test_new_line
302
+ before = [" "*10]*5
303
+ after = [ "hello ",
304
+ "world ",
305
+ " ",
306
+ " ",
307
+ " " ]
308
+ screen_modify_test(before, after) do |s|
309
+ s.feed_bytes("hello\nworld")
310
+ end
311
+ end
312
+
313
+ private
314
+
315
+ def screen_modify_test(start_with, expected, message=nil)
316
+ raise "no block given" unless block_given?
317
+
318
+ s = ScripTTY::Term::XTerm.new(start_with.length, start_with[0].length)
319
+ s.text = start_with
320
+
321
+ # Do the operation
322
+ yield s
323
+
324
+ # Compare
325
+ assert_equal expected, s.text, message
326
+ end
327
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../lib")
@@ -0,0 +1,131 @@
1
+ # = Tests for ScripTTY::Util::Transcript::Reader
2
+ # Copyright (C) 2010 Infonium Inc.
3
+ #
4
+ # This file is part of ScripTTY.
5
+ #
6
+ # ScripTTY is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # ScripTTY is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require File.dirname(__FILE__) + "/../../test_helper.rb"
20
+ require 'scriptty/util/transcript/reader'
21
+
22
+ class TranscriptReaderTest < Test::Unit::TestCase
23
+ def test_basic
24
+ input_lines = <<-'EOF'.split("\n").map{|line| line.strip}
25
+ [0.000] * "Informational message" "with argument" "\377"
26
+ [0.000] Copen "10.0.0.5" "55555"
27
+ [0.000] Sopen "10.0.0.1" "1234"
28
+ [0.001] C "alice\211\0010"
29
+ [0.001] S "bob\042"
30
+ [2.500] Cp "foo" "arg"
31
+ [2.900] Sp "." "arg"
32
+ [3.000] Sp "ESC" "\033"
33
+ [4.000] Cx "disconnect"
34
+ [5.000] Sx "disconnect"
35
+ [5.000] Sx
36
+ [5] Cx
37
+ EOF
38
+ expected = [
39
+ [0.0, :info, ["Informational message", "with argument", "\xff"]],
40
+ [0.0, :client_open, ["10.0.0.5", 55555]],
41
+ [0.0, :server_open, ["10.0.0.1", 1234]],
42
+ [0.001, :from_client, ["alice\x89\x01\x30"]],
43
+ [0.001, :from_server, ["bob\x22"]],
44
+ [2.5, :client_parsed, ["foo", "arg"]],
45
+ [2.9, :server_parsed, [".", "arg"]],
46
+ [3.0, :server_parsed, ["ESC", "\x1b"]],
47
+ [4.0, :client_close, ["disconnect"]],
48
+ [5.0, :server_close, ["disconnect"]],
49
+ [5.0, :server_close, []],
50
+ [5.0, :client_close, []],
51
+ ]
52
+ reader = ScripTTY::Util::Transcript::Reader.new
53
+ actual = input_lines.map{|line| reader.parse_line(line) }
54
+ assert_equal expected, actual
55
+ end
56
+
57
+ def test_bad_inputs
58
+ # Each line of the following must fail to parse
59
+ input_lines = <<-'EOF'.split("\n").map{|line| line.strip}
60
+ [0.000] * "Lone backslash" "\"
61
+ [0.000] * "Bad octal value" "\400"
62
+ [0.100] * "No quotes" foo
63
+ [0.200] $ "Unknown type"
64
+ [0.200] Copen "bad port" "10abc"
65
+ [0.200] Sopen "bad port" "10abc"
66
+ [0.300] * "Non-printableASCII characters" "Café"
67
+ [0.400] Cx "too much whitespace"
68
+ * "No timestamp"
69
+ [] * "Empty timestamp"
70
+ [5.5.5] "multiple decimals in timestamp"
71
+ EOF
72
+ reader = ScripTTY::Util::Transcript::Reader.new
73
+ input_lines.each do |line|
74
+ assert_raise(ArgumentError, line.inspect) do
75
+ reader.parse_line(line)
76
+ end
77
+ end
78
+
79
+ # Every escape, as encoded by ScripTTY::Util::Transcript::Writer, should
80
+ # parse correctly.
81
+ def test_escapes
82
+ input = '[99.000] S "\000\001\002\003\004\005\006\007'
83
+ input += '\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027'
84
+ input += '\030\031\032\033\034\035\036\037 !\042#$%&' + "'"
85
+ input += '()*+,-./0123456789:;<=>?'
86
+ input += '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\134]^_'
87
+ input += '`abcdefghijklmnopqrstuvwxyz{|}~\177'
88
+ input += '\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217'
89
+ input += '\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237'
90
+ input += '\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257'
91
+ input += '\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277'
92
+ input += '\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317'
93
+ input += '\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337'
94
+ input += '\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357'
95
+ input += '\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
96
+ input += "\"\n"
97
+ reader = ScripTTY::Util::Transcript::Reader.new
98
+ timestamp, type, args = reader.parse_line(input)
99
+ assert_equal 99.0, timestamp
100
+ assert_equal type, :from_server
101
+ assert_equal args, [(0..255).pack("C*")]
102
+ end
103
+
104
+ # Every octal escape between \000 and \377 should parse correctly.
105
+ def test_all_escapes
106
+ input = '[99.000] S "'
107
+ input += '\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017'
108
+ input += '\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037'
109
+ input += '\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057'
110
+ input += '\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077'
111
+ input += '\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117'
112
+ input += '\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137'
113
+ input += '\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157'
114
+ input += '\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177'
115
+ input += '\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217'
116
+ input += '\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237'
117
+ input += '\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257'
118
+ input += '\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277'
119
+ input += '\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317'
120
+ input += '\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337'
121
+ input += '\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357'
122
+ input += '\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
123
+ input += "\"\n"
124
+ reader = ScripTTY::Util::Transcript::Reader.new
125
+ timestamp, type, args = reader.parse_line(input)
126
+ assert_equal 99.0, timestamp
127
+ assert_equal type, :from_server
128
+ assert_equal args, [(0..255).pack("C*")]
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,126 @@
1
+ # = Tests for ScripTTY::Util::Transcript::Writer
2
+ # Copyright (C) 2010 Infonium Inc.
3
+ #
4
+ # This file is part of ScripTTY.
5
+ #
6
+ # ScripTTY is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # ScripTTY is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require File.dirname(__FILE__) + "/../../test_helper.rb"
20
+ require 'scriptty/util/transcript/writer'
21
+ require 'stringio'
22
+
23
+ class TranscriptWriterTest < Test::Unit::TestCase
24
+ def test_methods
25
+ sio = StringIO.new
26
+ writer = ScripTTY::Util::Transcript::Writer.new(sio)
27
+ writer.override_timestamp = 88.0
28
+ writer.client_open("10.0.0.5", 55555)
29
+ writer.server_open("10.0.0.1", 54321)
30
+ writer.from_client("\e[33m")
31
+ writer.from_server("\e[33m")
32
+ writer.client_parsed("t_foo", "\e[33m")
33
+ writer.server_parsed("t_foo", "\e[33m")
34
+ writer.client_close("msg")
35
+ writer.server_close("msg")
36
+ writer.info("msg")
37
+ writer.close
38
+ expected = <<-'EOF'.strip.split("\n").map{|line| line.strip}.join("\n") + "\n"
39
+ [88.000] Copen "10.0.0.5" "55555"
40
+ [88.000] Sopen "10.0.0.1" "54321"
41
+ [88.000] C "\033[33m"
42
+ [88.000] S "\033[33m"
43
+ [88.000] Cp "t_foo" "\033[33m"
44
+ [88.000] Sp "t_foo" "\033[33m"
45
+ [88.000] Cx "msg"
46
+ [88.000] Sx "msg"
47
+ [88.000] * "msg"
48
+ EOF
49
+ end
50
+
51
+ def test_string_encoding
52
+ sio = StringIO.new
53
+ writer = ScripTTY::Util::Transcript::Writer.new(sio)
54
+ writer.override_timestamp = 99.0
55
+ writer.from_client((0..255).to_a.pack("C*"))
56
+ writer.close
57
+
58
+ # Backslash, double-quotes, and non-printableASCII (characters outside the
59
+ # range \x20-\x7e) should be octal-encoded.
60
+ expected = '[99.000] C "\000\001\002\003\004\005\006\007'
61
+ expected += '\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027'
62
+ expected += '\030\031\032\033\034\035\036\037 !\042#$%&' + "'"
63
+ expected += '()*+,-./0123456789:;<=>?'
64
+ expected += '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\134]^_'
65
+ expected += '`abcdefghijklmnopqrstuvwxyz{|}~\177'
66
+ expected += '\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217'
67
+ expected += '\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237'
68
+ expected += '\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257'
69
+ expected += '\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277'
70
+ expected += '\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317'
71
+ expected += '\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337'
72
+ expected += '\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357'
73
+ expected += '\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
74
+ expected += "\"\n"
75
+ assert_equal expected, sio.string
76
+ end
77
+
78
+ # Check that the timestamp of the first message is zero, or within the amount
79
+ # of time it took to instantiate the writer and emit the first line.
80
+ def test_initial_timestamp
81
+ sio = StringIO.new
82
+ t0 = Time.now
83
+ writer = ScripTTY::Util::Transcript::Writer.new(sio)
84
+ writer.info("foo")
85
+ t1 = Time.now
86
+ assert sio.string =~ /^\[([\d.]+)\]/
87
+ relative_timestamp = $1
88
+ assert !relative_timestamp.empty?
89
+ relative_timestamp = relative_timestamp.to_f # convert to float
90
+ assert (relative_timestamp >= 0.0 && relative_timestamp <= (t1 - t0))
91
+ end
92
+
93
+ # Check that timestamps increase
94
+ def test_timestamps_increase
95
+ sio = StringIO.new
96
+ writer = ScripTTY::Util::Transcript::Writer.new(sio)
97
+ last_timestamp = 0.0
98
+ 200.times do
99
+ sleep 0.002 # make sure the time increases enough to be within the resolution of the timestamp
100
+ writer.info("foo")
101
+ assert sio.string.strip.split("\n").last =~ /^\[([\d.]+)\]/
102
+ current_timestamp = $1.to_f
103
+ assert current_timestamp > last_timestamp, "timestamps should increase"
104
+ last_timestamp = current_timestamp
105
+ end
106
+ end
107
+
108
+ # Test the override_timestamp attribute
109
+ def test_override_timestamp
110
+ sio = StringIO.new
111
+ writer = ScripTTY::Util::Transcript::Writer.new(sio)
112
+ writer.override_timestamp = 1.0 ; writer.info("one") ; sleep 0.02; writer.info("two")
113
+ writer.override_timestamp = 3.101 ; writer.info("three")
114
+ writer.override_timestamp = 4.222 ; writer.info("four")
115
+ writer.override_timestamp = 5.001 ; writer.info("five")
116
+ writer.close
117
+ expected = <<-'EOF'.strip.split("\n").map{|line| line.strip}.join("\n") + "\n"
118
+ [1.000] * "one"
119
+ [1.000] * "two"
120
+ [3.101] * "three"
121
+ [4.222] * "four"
122
+ [5.001] * "five"
123
+ EOF
124
+ assert_equal expected, sio.string
125
+ end
126
+ end
data/test.watchr ADDED
@@ -0,0 +1,29 @@
1
+ # = autowatchr script for continuous testing of ScripTTY
2
+ # == Instructions
3
+ # - Install the 'watchr' and 'autowatchr' gems
4
+ # - Run "watchr test.watchr"
5
+
6
+ require 'autowatchr'
7
+
8
+ # Fixup mapping between files in lib/ and corresponding tests in test/
9
+ class ::Autowatchr # reopen
10
+ # Take a path like "lib/scriptty/foo/bar.rb" and run the corresponding test "test/foo/bar_test.rb"
11
+ def run_lib_file(path)
12
+ path_segments = path.split(File::SEPARATOR).reject{|s| s.empty?}
13
+ basename = path_segments.pop
14
+ path_segments.shift # Remove "lib"
15
+ path_segments.shift # Remove "scriptty"
16
+ path_segments.unshift @config.test_dir # Prepend "test"
17
+ path_segments << basename.gsub(/\.rb\Z/, "") + "_test.rb" # append test name
18
+ run_test_file(File.join(*path_segments))
19
+ end
20
+ end
21
+
22
+ Autowatchr.new(self) do |config|
23
+ config.ruby = ENV['RUBY'] || 'ruby'
24
+ config.lib_dir = 'lib'
25
+ config.test_dir = 'test'
26
+ config.test_re = /^.*_test\.rb\Z/
27
+ end
28
+
29
+ # vim:set ft=ruby: