scriptty 0.5.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: