xmodem 0.1.0

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.
data/lib/xmodem.rb ADDED
@@ -0,0 +1,323 @@
1
+ # Author:: Jonno Downes (jonno@jamtronix.com)
2
+ # Contrib:: Sten Feldman (exile@chamber.ee)
3
+ #
4
+ # License:: Mozilla Public License 1.1
5
+ #
6
+ # Doesn't seem to work for me using Ruby 2.0 - BORKEN unless fixed
7
+ #
8
+ # Public interface changes:
9
+ # - ModemProtocols renamed to XMODEM
10
+ # - xmodem_tx renamed to send
11
+ # - xmodem_rx renamed to receive
12
+ # - Logger outputs reflect the actors sender/receiver
13
+
14
+ require 'log4r'
15
+ include Log4r
16
+
17
+ module XMODEM
18
+
19
+ XMODEM_BLOCK_SIZE = 128 #how many bytes (ecluding header & checksum) in each block?
20
+ XMODEM_MAX_TIMEOUTS = 5 #how many timeouts in a row before the sender gives up?
21
+ XMODEM_MAX_ERRORS = 10 #how many errors on a single block before the receiver gives up?
22
+
23
+ XMODEM_CRC_ATTEMPTS = 3 #how many times should receiver attempt to use CRC?
24
+ LOG_NAME='XModem'
25
+ @timeout_seconds = 5.0 #default timeout period
26
+
27
+ #how long does the protocol wait before giving up?
28
+ def XMODEM::timeout_seconds
29
+ @timeout_seconds
30
+ end
31
+
32
+ def XMODEM::timeout_seconds=(val)
33
+ @timeout_seconds=val
34
+ end
35
+
36
+ # receive a file using XMODEM protocol (block size = 128 bytes)
37
+ # remote:: must be an IO object connected to an XMODEM sender
38
+ # local:: must be an IO object - the inbound file (trimmed of any final padding) will be written to this
39
+ # options:: hash of options. options are: values :crc (use 16bit CRC instead of 8 bit checksum)
40
+ # - :mode=> :crc or :checksum (default is 8 bit checksum)
41
+ #
42
+ def XMODEM::receive(remote,local,options=nil)
43
+
44
+ mode = ( (options.nil?) || options[:mode].nil? ) ? :checksum : options[:mode]
45
+
46
+ logger.debug "receiver: XMODEM - #{mode}"
47
+ #flush the input buffer
48
+ loop do
49
+ break if (select([remote],nil,nil,0.01).nil?)
50
+ remote.getc
51
+ end
52
+
53
+ #trigger sending
54
+ case mode
55
+ when :crc
56
+ XMODEM_CRC_ATTEMPTS.times do |attempt|
57
+ remote.putc('C')
58
+ break unless (select([remote],nil,nil,timeout_seconds).nil?)
59
+ #if we don't get a response, fall back to checksum mode
60
+ if attempt==XMODEM_CRC_ATTEMPTS-1 then
61
+ logger.warn "receiver: crc-16 request failed, falling back to checksum mode"
62
+ remote.putc(NAK)
63
+ mode=:checksum
64
+ end
65
+ end
66
+ else
67
+ remote.putc(NAK)
68
+ end
69
+
70
+ expected_block = 1
71
+ error_count = 0
72
+ last_block = ""
73
+ data = ""
74
+ loop do
75
+
76
+ begin
77
+ rx_cmd = receive_getbyte(remote).ord
78
+
79
+ if rx_cmd == EOT then
80
+ remote.putc(ACK)
81
+ trimmed_block=last_block.sub(/(\x1A+)\Z/,'')
82
+ local<< trimmed_block#trim any trailing FILLER characters in last block
83
+ break
84
+ end
85
+
86
+ if rx_cmd!=SOH then
87
+ logger.warn "receiver: expected SOH (0x#{SOH}) got 0x#{"%x" % rx_cmd} - pos = #{remote.pos}"
88
+ next
89
+ end
90
+
91
+ data=""
92
+ block= receive_getbyte(remote).ord
93
+ block_check = receive_getbyte(remote).ord
94
+ validity = :valid
95
+ validity = :invalid unless (block_check + block)==0xFF
96
+
97
+ logger.debug "receiver: #{validity} block number 0x#{"%02x" % block} / block number check 0x#{"%02x" % block_check}"
98
+ logger.debug "receiver: receiving block #{block} / expected block #{expected_block}"
99
+
100
+ raise RXSynchError if block != expected_block && block != ((expected_block-1) % 0x100)
101
+
102
+ if (block==expected_block) && (validity==:valid) then
103
+ local<<last_block
104
+ last_block=""
105
+ end
106
+ XMODEM_BLOCK_SIZE.times do
107
+ b=(receive_getbyte(remote))
108
+ data<<b
109
+ Thread.pass
110
+ end
111
+
112
+ check_ok=false
113
+
114
+ case mode
115
+ when :crc
116
+ rx_crc = ( receive_getbyte(remote).ord<<8) + receive_getbyte(remote).ord
117
+ crc = ccitt16_crc(data)
118
+ check_ok = (crc==rx_crc)
119
+ if !check_ok then
120
+ logger.warn "receiver: invalid crc-16 for block #{block}: calculated 0x#{'%04x' % crc}, got 0x#{'%02x' % rx_crc}"
121
+ end
122
+ else
123
+ rx_checksum = receive_getbyte(remote).ord
124
+ checksum = XMODEM::checksum(data)
125
+ check_ok = (checksum == rx_checksum)
126
+ if !check_ok then
127
+ logger.warn "receiver: invalid checksum for block #{block}: calculated 0x#{'%02x' % checksum}, got 0x#{'%02x' % rx_checksum}"
128
+ end
129
+ end
130
+
131
+ if (check_ok) then
132
+ last_block = data
133
+ logger.debug "receiver: #{mode} test passed for block #{block}"
134
+ remote.putc(ACK)
135
+ if (block == expected_block) then
136
+ expected_block = ((expected_block+1) % 0x100)
137
+ error_count=0 #reset the error count
138
+ end
139
+ else
140
+ remote.putc(NAK)
141
+ error_count+=1
142
+ logger.warn "receiver: checksum error # #{error_count} / max #{XMODEM_MAX_ERRORS}"
143
+ raise RXChecksumError.new("too many receive errors on block #{block}") if error_count>XMODEM_MAX_ERRORS
144
+ end
145
+ rescue RXTimeout
146
+ error_count+=1
147
+ logger.warn "receiver: timeout error # #{error_count} / max #{XMODEM_MAX_ERRORS}"
148
+ raise RXTimeout("too many receive errors on block #{block}").new if error_count>XMODEM_MAX_ERRORS
149
+ end
150
+ end
151
+
152
+ logger.info "receive complete"
153
+ end
154
+
155
+ # send a file using standard XMODEM protocol (block size = 128 bytes)
156
+ # will use CRC mode if requested by sender, else use 8-bit checksum
157
+ # remote:: must be an IO object connected to an XMODEM receiver
158
+ # local:: must be an IO object containing the data to be sent
159
+ def XMODEM::send(remote,local)
160
+ block_number=1
161
+ current_block=""
162
+ sent_eot=false
163
+
164
+ XMODEM_BLOCK_SIZE.times do
165
+ b=(local.eof? ? FILLER : local.getc)
166
+ current_block<<b.chr
167
+ Thread.pass
168
+ end
169
+ checksum = XMODEM::checksum(current_block)
170
+ mode=:checksum
171
+ loop do
172
+ logger.info "sender: waiting for ACK/NAK/CAN (eot_sent: #{sent_eot})"
173
+ if select([remote],nil,nil,timeout_seconds*XMODEM_MAX_TIMEOUTS).nil? then
174
+ raise RXTimeout.new("timeout waiting for input on tx (#{timeout_seconds*XMODEM_MAX_TIMEOUTS} seconds)") unless sent_eot
175
+ logger.info "sender: timeout waiting for ACK of EOT"
176
+ return
177
+ end
178
+ if remote.eof? then
179
+ logger.warn "sender: unexpected eof on input"
180
+ break
181
+ end
182
+ tx_cmd=remote.getc.ord
183
+ logger.debug "sendder: got 0x#{"%x" % tx_cmd}"
184
+ if tx_cmd==ACK then
185
+ if sent_eot then
186
+ logger.debug "sender: got ACK of EOT"
187
+ break
188
+ end
189
+
190
+ if local.eof? then
191
+ remote.putc(EOT)
192
+ logger.debug "sender: got ACK of last block"
193
+ sent_eot=true
194
+ next
195
+ end
196
+ block_number=((block_number+1)%0x100)
197
+ current_block=""
198
+ XMODEM_BLOCK_SIZE.times do
199
+ b=(local.eof? ? FILLER : local.getc)
200
+ current_block<<b
201
+ Thread.pass
202
+ end
203
+
204
+ elsif (block_number==1) && (tx_cmd==CRC_MODE) then
205
+ mode=:crc
206
+ logger.debug "sender: using crc-16 mode"
207
+ end
208
+
209
+ next unless [ACK,NAK,CRC_MODE].include?(tx_cmd.ord)
210
+ logger.info "sender: sending block #{block_number}"
211
+ remote.putc(SOH) #start of block
212
+ remote.putc(block_number) #block number
213
+ remote.putc(0xff-block_number) #1's complement of block number
214
+ current_block.each_byte {|b| remote.putc(b)}
215
+ case mode
216
+ when :crc then
217
+ crc = ccitt16_crc (current_block)
218
+ remote.putc(crc >> 8) #crc hi byte
219
+ remote.putc(crc & 0xFF) #crc lo byte
220
+ logger.debug "sender: crc-16 for block #{block_number}:#{ "%04x" % crc}"
221
+ else
222
+ checksum = XMODEM::checksum(current_block)
223
+ remote.putc(checksum)
224
+ logger.debug "sender: checksum for block #{block_number}:#{ "%02x" % checksum}"
225
+ end
226
+
227
+ end
228
+ logger.info "sending complete (eot_sent: #{sent_eot})"
229
+ end
230
+
231
+ #calculate an 8-bit XMODEM checksum
232
+ #this is just the sum of all bytes modulo 0x100
233
+ def XMODEM::checksum(block)
234
+ raise RXChecksumError.new("checksum requested of invalid block {size should be #{XMODEM_BLOCK_SIZE}, was #{block.length}") unless block.length==XMODEM_BLOCK_SIZE
235
+ checksum=0
236
+ block.each_byte do |b|
237
+ checksum = (checksum+b) % 0x100
238
+ end
239
+ checksum
240
+ end
241
+
242
+ #calculate a 16-bit CRC
243
+ def XMODEM::ccitt16_crc(block)
244
+ # cribbed from http://www.hadermann.be/blog/32/ruby-crc16-implementation/
245
+ raise RXChecksumError.new("checksum requested of invalid block {size should be #{XMODEM_BLOCK_SIZE}, was #{block.length}") unless block.length==XMODEM_BLOCK_SIZE
246
+ crc=0
247
+ block.each_byte{|x| crc = ((crc<<8) ^ CCITT_16[(crc>>8) ^ x])&0xffff}
248
+ crc
249
+ end
250
+
251
+ private
252
+
253
+ SOH = 0x01
254
+ STX = 0x02
255
+ EOT = 0x04
256
+ ACK = 0x06
257
+ NAK = 0x15
258
+ CAN = 0x18
259
+ CRC_MODE = 0x43 #'C'
260
+ FILLER = 0x1A
261
+
262
+ CCITT_16 = [
263
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
264
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
265
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
266
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
267
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
268
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
269
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
270
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
271
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
272
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
273
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
274
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
275
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
276
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
277
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
278
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
279
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
280
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
281
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
282
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
283
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
284
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
285
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
286
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
287
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
288
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
289
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
290
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
291
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
292
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
293
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
294
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
295
+ ]
296
+
297
+ def XMODEM::receive_getbyte(remote)
298
+
299
+ if (select([remote],nil,nil,timeout_seconds).nil?) then
300
+ remote.putc(NAK)
301
+ raise RXTimeout
302
+ end
303
+
304
+ raise RXSynchError if remote.eof?
305
+ remote.getc
306
+ end
307
+
308
+
309
+ def XMODEM::logger
310
+ Logger.new(LOG_NAME) if Logger[LOG_NAME].nil?
311
+ Logger[LOG_NAME]
312
+ end
313
+
314
+ class RXTimeout < RuntimeError
315
+ end
316
+
317
+ class RXChecksumError < RuntimeError
318
+ end
319
+
320
+ class RXSynchError < RuntimeError
321
+ end
322
+
323
+ end
@@ -0,0 +1,3 @@
1
+ module XMODEM
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,280 @@
1
+ #make sure the relevant folder with our libraries is in the require path
2
+ lib_path=File.expand_path(File.dirname(__FILE__)+"//..//lib")
3
+ $:.unshift(lib_path) unless $:.include?(lib_path)
4
+
5
+ require 'versioncheck'
6
+ require 'xmodem/version'
7
+
8
+ rb_vc = VersionCheck.rubyversion
9
+ if !rb_vc.have_version?(2,1)
10
+ require 'simplecov'
11
+ SimpleCov.command_name 'MiniTest'
12
+ SimpleCov.start
13
+ end
14
+
15
+ if ENV['TRAVIS'] == "true" && ENV['CI'] =="true"
16
+ require 'coveralls'
17
+ Coveralls.wear!
18
+ end
19
+
20
+ require 'minitest/autorun'
21
+ require 'minitest/reporters'
22
+
23
+ MiniTest::Reporters.use!
24
+
25
+ require 'xmodem'
26
+ require 'socket'
27
+ require 'stringio'
28
+
29
+ Thread.abort_on_exception = true
30
+
31
+ XMODEM::logger.outputters = Outputter.stdout
32
+
33
+ XMODEM::timeout_seconds=0.4 #so we don't wait so long for retransmissions
34
+
35
+ LOCAL_PORT=9999
36
+
37
+ module CorruptIn
38
+ attr_accessor :real_getc,:corruption_frequency
39
+
40
+ def getc
41
+ @char_count=0 if @char_count.nil?
42
+
43
+ raise "real_getc not initialised" if @real_getc.nil?
44
+ b=@real_getc.call
45
+ @char_count+=1
46
+ if ((@char_count % @corruption_frequency)==0) then
47
+ corrupted_char=0xff-b.ord
48
+ $stdout.puts "corrupting : 0x%02x -> 0x%02x" % [b.ord,corrupted_char]
49
+ b=corrupted_char.chr
50
+ end
51
+ return b
52
+ end
53
+
54
+ end
55
+
56
+ module CorruptOut
57
+ attr_accessor :real_putc,:corruption_frequency
58
+
59
+ def putc (b)
60
+ @char_count=0 if @char_count.nil?
61
+
62
+ raise "real_putc not initialised" if @real_putc.nil?
63
+ @char_count+=1
64
+ if ((@char_count % @corruption_frequency)==0) then
65
+ corrupted_char=0xff-b
66
+ $stdout.puts "corrupting : 0x%02x -> 0x%02x" % [b,corrupted_char]
67
+ b=corrupted_char
68
+ end
69
+ @real_putc.call(b)
70
+
71
+ end
72
+ end
73
+
74
+
75
+ module DropIn
76
+ attr_accessor :real_getc,:drop_frequency
77
+
78
+ def getc
79
+ @char_count=0 if @char_count.nil?
80
+
81
+ raise "real_getc not initialised" if @real_getc.nil?
82
+ b=@real_getc.call
83
+ @char_count+=1
84
+ if ((@char_count % @drop_frequency)==0) then
85
+ $stdout.puts "dropping : 0x%02x " % [b.ord]
86
+ @real_getc.call
87
+ end
88
+ return b
89
+ end
90
+ end
91
+
92
+ module DropOut
93
+ attr_accessor :real_putc,:drop_frequency
94
+
95
+ def putc (b)
96
+ @char_count=0 if @char_count.nil?
97
+
98
+ raise "real_putc not initialised" if @real_putc.nil?
99
+ @char_count+=1
100
+ if ((@char_count % @drop_frequency)==0) then
101
+ $stdout.puts "dropping : 0x%02x " % [b]
102
+ else
103
+ @real_putc.call(b)
104
+ end
105
+ end
106
+ end
107
+
108
+ class XmodemTests < MiniTest::Test
109
+
110
+ @@server=nil
111
+ @@unix_socket = "/tmp/xmodem-test.sock"
112
+
113
+ def sendfile(file)
114
+ if @@server.nil? then
115
+ if ENV['OS'] != "Windows_NT"
116
+ File.delete( @@unix_socket ) if FileTest.exists?( @@unix_socket )
117
+ @@server = UNIXServer.new(@@unix_socket)
118
+ else
119
+ @@server = TCPServer.new(LOCAL_PORT)
120
+ end
121
+ else
122
+ puts "reusing existing server"
123
+ end
124
+ session = @@server.accept
125
+ session.sync=true
126
+ puts "Connected (sendfile)"
127
+ XMODEM::send(session,file)
128
+ session.close
129
+ end
130
+
131
+ def acceptfile(file,error_type=nil,error_frequency=nil,rx_options=nil)
132
+ if ENV['OS'] != "Windows_NT"
133
+ socket = UNIXSocket.open(@@unix_socket)
134
+ else
135
+ socket = TCPSocket.new('localhost', LOCAL_PORT)
136
+ end
137
+ socket.sync=true
138
+ puts "Connected (acceptfile)"
139
+ if !error_frequency.nil? then
140
+ real_getc=socket.method(:getc)
141
+
142
+ case error_type
143
+ when :corruption_in
144
+ real_getc=socket.method(:getc)
145
+ socket.extend(CorruptIn)
146
+ socket.corruption_frequency=error_frequency
147
+ socket.real_getc=real_getc
148
+ when :packet_loss_in
149
+ real_getc=socket.method(:getc)
150
+ socket.extend(DropIn)
151
+ socket.drop_frequency=error_frequency
152
+ socket.real_getc=real_getc
153
+ when :packet_loss_out
154
+ real_putc=socket.method(:putc)
155
+ socket.extend(DropOut)
156
+ socket.drop_frequency=error_frequency
157
+ socket.real_putc=real_putc
158
+ when :corruption_out
159
+ real_putc=socket.method(:putc)
160
+ socket.extend(CorruptOut)
161
+ socket.corruption_frequency=error_frequency
162
+ socket.real_putc=real_putc
163
+ else
164
+ raise "unknown error_type #{error_type}"
165
+ end
166
+ file.flush
167
+ end
168
+ XMODEM::receive(socket,file,rx_options)
169
+ loop {Thread.pass} until socket.closed?
170
+
171
+ end
172
+
173
+ def do_test(tx_file,rx_file,error_type=nil,error_frequency=nil,rx_options=nil)
174
+ test_description="test type: #{error_type}"
175
+ test_description+=" (freq=#{error_frequency})" unless error_frequency.nil?
176
+ made_tx = false
177
+ made_rx = false
178
+ if !(tx_file.respond_to?(:getc))
179
+ tx_filename=tx_file
180
+ tx_file=File.new(tx_filename,"rb")
181
+ made_tx = true
182
+ else
183
+ tx_filename=tx_file.class
184
+ tx_file.rewind
185
+ end
186
+
187
+
188
+ if !(rx_file.respond_to?(:putc))
189
+ rx_filename=rx_file
190
+ rx_file=File.new(rx_filename,"wb+")
191
+ made_rx = true
192
+ else
193
+ rx_filename=rx_file.class
194
+ rx_file.rewind
195
+ end
196
+ puts "#{test_description} : #{tx_filename}->#{rx_filename}"
197
+
198
+
199
+ tx_thread=Thread.new {sendfile(tx_file)}
200
+ sleep(0.1) # Time for the socket to be opened
201
+ rx_thread=Thread.new {acceptfile(rx_file,error_type,error_frequency,rx_options)}
202
+ loop do
203
+ break unless tx_thread.alive?
204
+ break unless rx_thread.alive?
205
+ sleep(0.01) #wake up occasionally to get keyboard input, so we break on ^C
206
+ end
207
+ tx_file.rewind
208
+ rx_file.rewind
209
+ rx_filecontents=rx_file.read
210
+ tx_filecontents=tx_file.read
211
+ assert_equal(tx_filecontents.length,rx_filecontents.length,"file length correct after round trip")
212
+ assert_equal(tx_filecontents,rx_filecontents,"file contents correct after round trip")
213
+
214
+ tx_file.close if made_tx
215
+ rx_file.close if made_rx
216
+
217
+ File.delete(rx_filename) if made_rx
218
+ end
219
+
220
+ ##
221
+ # Teardown
222
+ def teardown
223
+ unless ENV['OS'] == "Windows_NT"
224
+ File.delete( @@unix_socket ) if FileTest.exist?( @@unix_socket )
225
+ end
226
+ end
227
+
228
+ # Test cases
229
+ def test_version
230
+ assert_equal("0.1.0", ::XMODEM::VERSION)
231
+ end
232
+
233
+ def test_checksum
234
+ assert_equal(0, XMODEM::checksum( "\000"*128))
235
+ assert_equal(128, XMODEM::checksum("\001"*128))
236
+ assert_equal(0, XMODEM::checksum("\002"*128))
237
+ assert_equal(128, XMODEM::checksum("\003"*128))
238
+ end
239
+
240
+ def test_all
241
+ sample_text_file="sample.test.txt"
242
+ sample_bin_file="sample.test.bin"
243
+ f=File.new(sample_text_file,"w")
244
+ f<<File.new(__FILE__,"r").read
245
+ f.close
246
+
247
+ f = File.new(sample_bin_file,"wb")
248
+ 2000.times { |i| f << (i % 0x100).chr}
249
+ f.close
250
+
251
+ txstring_io=StringIO.new("this is a test string")
252
+ rxstring_io=StringIO.new("")
253
+
254
+ do_test(sample_text_file, "crc-simple.test.txt", nil, nil, {:mode=>:crc})
255
+ do_test(sample_bin_file, "crc-simple.test.bin", nil, nil, {:mode=>:crc})
256
+ do_test(txstring_io,rxstring_io)
257
+ do_test(sample_text_file,"corrupt-crc.test.txt",:corruption_in,700,{:mode=>:crc})
258
+
259
+ do_test(txstring_io,rxstring_io)
260
+ do_test(sample_text_file,rxstring_io)
261
+ do_test(sample_text_file,"simple.test.txt")
262
+ do_test(sample_bin_file,"corrupt_out.test.bin",:corruption_out,4)
263
+ do_test(sample_text_file,"packet_loss_out.test.txt",:packet_loss_out,3)
264
+ do_test(sample_text_file,"packet_loss_in.test.txt",:packet_loss_in,200)
265
+
266
+ do_test(sample_text_file,"corrupt.test.txt",:corruption_in,700)
267
+ do_test(sample_text_file,"very_corrupt.test.txt",:corruption_in,200)
268
+
269
+ do_test(sample_bin_file,"simple.test.bin")
270
+ do_test(sample_bin_file,"corrupt.test.bin",:corruption_in,700)
271
+
272
+ bigstring=""
273
+ 512.times {|i| bigstring<<((i%0x100).chr*128)}
274
+ do_test(StringIO.new(bigstring),"bigfile.test.txt")
275
+
276
+ File.delete(sample_text_file, sample_bin_file)
277
+
278
+ end
279
+
280
+ end