packetfu 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.gitignore +3 -0
  2. data/INSTALL.rdoc +40 -0
  3. data/LICENSE.txt +25 -0
  4. data/examples/100kpackets.rb +41 -0
  5. data/examples/ackscan.rb +38 -0
  6. data/examples/arp.rb +60 -0
  7. data/examples/arphood.rb +59 -0
  8. data/examples/dissect_thinger.rb +22 -0
  9. data/examples/ethernet.rb +10 -0
  10. data/examples/examples.rb +3 -0
  11. data/examples/ids.rb +4 -0
  12. data/examples/idsv2.rb +6 -0
  13. data/examples/new-simple-stats.rb +52 -0
  14. data/examples/oui.txt +84177 -0
  15. data/examples/packetfu-shell.rb +113 -0
  16. data/examples/simple-sniffer.rb +40 -0
  17. data/examples/simple-stats.rb +50 -0
  18. data/examples/slammer.rb +33 -0
  19. data/examples/uniqpcap.rb +15 -0
  20. data/lib/packetfu.rb +147 -0
  21. data/lib/packetfu/capture.rb +169 -0
  22. data/lib/packetfu/config.rb +58 -0
  23. data/lib/packetfu/inject.rb +65 -0
  24. data/lib/packetfu/packet.rb +533 -0
  25. data/lib/packetfu/pcap.rb +594 -0
  26. data/lib/packetfu/protos/arp.rb +268 -0
  27. data/lib/packetfu/protos/eth.rb +296 -0
  28. data/lib/packetfu/protos/hsrp.rb +206 -0
  29. data/lib/packetfu/protos/icmp.rb +179 -0
  30. data/lib/packetfu/protos/invalid.rb +55 -0
  31. data/lib/packetfu/protos/ip.rb +378 -0
  32. data/lib/packetfu/protos/ipv6.rb +250 -0
  33. data/lib/packetfu/protos/tcp.rb +1127 -0
  34. data/lib/packetfu/protos/udp.rb +240 -0
  35. data/lib/packetfu/structfu.rb +294 -0
  36. data/lib/packetfu/utils.rb +194 -0
  37. data/lib/packetfu/version.rb +50 -0
  38. data/packetfu.gemspec +21 -0
  39. data/setup.rb +1586 -0
  40. data/test/all_tests.rb +41 -0
  41. data/test/ethpacket_spec.rb +74 -0
  42. data/test/packet_spec.rb +73 -0
  43. data/test/packet_subclasses_spec.rb +13 -0
  44. data/test/packetfu_spec.rb +90 -0
  45. data/test/ptest.rb +16 -0
  46. data/test/sample-ipv6.pcap +0 -0
  47. data/test/sample.pcap +0 -0
  48. data/test/sample2.pcap +0 -0
  49. data/test/sample_hsrp_pcapr.cap +0 -0
  50. data/test/structfu_spec.rb +335 -0
  51. data/test/tcp_spec.rb +101 -0
  52. data/test/test_arp.rb +135 -0
  53. data/test/test_eth.rb +91 -0
  54. data/test/test_hsrp.rb +20 -0
  55. data/test/test_icmp.rb +54 -0
  56. data/test/test_inject.rb +31 -0
  57. data/test/test_invalid.rb +28 -0
  58. data/test/test_ip.rb +69 -0
  59. data/test/test_ip6.rb +68 -0
  60. data/test/test_octets.rb +37 -0
  61. data/test/test_packet.rb +174 -0
  62. data/test/test_pcap.rb +209 -0
  63. data/test/test_structfu.rb +112 -0
  64. data/test/test_tcp.rb +327 -0
  65. data/test/test_udp.rb +73 -0
  66. data/test/vlan-pcapr.cap +0 -0
  67. metadata +85 -6
data/test/all_tests.rb ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Tested on:
4
+ #
5
+ # ruby-1.9.3-head [ x86_64 ]
6
+ # ruby-1.9.1-p378 [ x86_64 ]
7
+ # ruby-1.8.6-p399 [ x86_64 ]
8
+ # ruby-1.8.7-p334 [ x86_64 ]
9
+ # ruby-1.9.2-p180 [ x86_64 ]
10
+
11
+ # Okay so the regular test/unit stuff screws up some of my
12
+ # meta magic. I need to move these over to spec and see
13
+ # if they're any better. In the meantime, behold my
14
+ # ghetto test exec()'er. It all passes with this,
15
+ # so I'm just going to go ahead and assume the testing
16
+ # methodolgy is flawed. TODO: rewrite all this for spec
17
+ # and incidentally get the gem to test like it's supposed
18
+ # to.
19
+
20
+ $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib/")
21
+ require 'packetfu'
22
+ puts "Testing PacketFu v#{PacketFu::VERSION}"
23
+ dir = Dir.new(File.dirname(__FILE__))
24
+
25
+ dir.each { |file|
26
+ next unless File.file? file
27
+ next unless file[/^test_.*rb$/]
28
+ next if file == $0
29
+ puts "Running #{file}..."
30
+ cmd = %x{ruby #{file}}
31
+ if cmd[/ 0 failures/] && cmd[/ 0 errors/]
32
+ puts "#{file}: All passed"
33
+ else
34
+ puts "File: #{file} had failures or errors:"
35
+ puts "-" * 80
36
+ puts cmd
37
+ puts "-" * 80
38
+ end
39
+ }
40
+
41
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
@@ -0,0 +1,74 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ include PacketFu
5
+
6
+ describe EthPacket, "when read from a pcap file" do
7
+
8
+ before :all do
9
+ parsed_packets = PcapFile.read_packets(File.join(".","sample.pcap"))
10
+ @eth_packet = parsed_packets.first
11
+ end
12
+
13
+ context "is a regular ethernet packet" do
14
+
15
+ subject { @eth_packet }
16
+
17
+ it "should be an EthPacket kind of packet" do
18
+ subject.should be_kind_of EthPacket
19
+ end
20
+
21
+ it "should have a dest mac address" do
22
+ subject.eth_daddr.should == "00:03:2f:1a:74:de"
23
+ end
24
+
25
+ it "should have a source mac address" do
26
+ subject.eth_saddr.should == "00:1b:11:51:b7:ce"
27
+ end
28
+
29
+ its(:size) { should == 78 }
30
+
31
+ it "should have a payload in its first header" do
32
+ subject.headers.first.body.should_not be_nil
33
+ end
34
+
35
+ context "an EthPacket's first header" do
36
+
37
+ subject { @eth_packet.headers.first }
38
+
39
+ it "should be 64 bytes" do
40
+ subject.body.sz.should == 64
41
+ end
42
+
43
+ context "EthHeader struct members" do
44
+ if RUBY_VERSION =~ /^1\.8/
45
+ its(:members) { should include :eth_dst.to_s }
46
+ its(:members) { should include :eth_src.to_s }
47
+ its(:members) { should include :eth_proto.to_s }
48
+ its(:members) { should include :body.to_s }
49
+ else
50
+ its(:members) { should include :eth_dst }
51
+ its(:members) { should include :eth_src }
52
+ its(:members) { should include :eth_proto }
53
+ its(:members) { should include :body }
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ context "isn't a regular Ethernet packet" do
62
+
63
+ subject {
64
+ parsed_packets = PcapFile.read_packets(File.join(".","vlan-pcapr.cap"))
65
+ parsed_packets.first
66
+ }
67
+
68
+ it "should not be an EthPacket" do
69
+ subject.should_not be_kind_of EthPacket
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,73 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ describe PacketFu::Packet, "abstract packet class behavior" do
5
+
6
+ before(:all) do
7
+ class PacketFu::FooPacket < PacketFu::Packet; end
8
+ class PacketFu::BarPacket < PacketFu::Packet; end
9
+ end
10
+
11
+ it "should not be instantiated" do
12
+ expect { PacketFu::Packet.new }.to raise_error(NoMethodError)
13
+ end
14
+
15
+ it "should allow subclasses to instantiate" do
16
+ expect { PacketFu::FooPacket.new }. to be
17
+ PacketFu.packet_classes.include?(PacketFu::FooPacket).should be_true
18
+ end
19
+
20
+ it "should register packet classes with PacketFu" do
21
+ PacketFu.packet_classes {should include(FooPacket) }
22
+ PacketFu.packet_classes {should include(BarPacket) }
23
+ end
24
+
25
+ it "should disallow badly named subclasses" do
26
+ expect {
27
+ class PacketFu::PacketNot < PacketFu::Packet
28
+ end
29
+ }.to raise_error
30
+ PacketFu.packet_classes.include?(PacketFu::PacketNot).should be_false
31
+ PacketFu.packet_classes {should_not include(PacketNot) }
32
+ end
33
+
34
+ before(:each) do
35
+ @tcp_packet = PacketFu::TCPPacket.new
36
+ @tcp_packet.ip_saddr = "10.10.10.10"
37
+ end
38
+
39
+ it "should shallow copy with dup()" do
40
+ p2 = @tcp_packet.dup
41
+ p2.ip_saddr = "20.20.20.20"
42
+ p2.ip_saddr.should == @tcp_packet.ip_saddr
43
+ p2.headers[1].object_id.should == @tcp_packet.headers[1].object_id
44
+ end
45
+
46
+ it "should deep copy with clone()" do
47
+ p3 = @tcp_packet.clone
48
+ p3.ip_saddr = "30.30.30.30"
49
+ p3.ip_saddr.should_not == @tcp_packet.ip_saddr
50
+ p3.headers[1].object_id.should_not == @tcp_packet.headers[1].object_id
51
+ end
52
+
53
+ it "should have senisble equality" do
54
+ p4 = @tcp_packet.dup
55
+ p4.should == @tcp_packet
56
+ p5 = @tcp_packet.clone
57
+ p5.should == @tcp_packet
58
+ end
59
+
60
+ # It's actually kinda hard to manually create identical TCP packets
61
+ it "should be possible to manually create identical packets" do
62
+ p6 = @tcp_packet.clone
63
+ p6.should == @tcp_packet
64
+ p7 = PacketFu::TCPPacket.new
65
+ p7.ip_saddr = p6.ip_saddr
66
+ p7.ip_id = p6.ip_id
67
+ p7.tcp_seq = p6.tcp_seq
68
+ p7.tcp_src = p6.tcp_src
69
+ p7.tcp_sum = p6.tcp_sum
70
+ p7.should == p6
71
+ end
72
+
73
+ end
@@ -0,0 +1,13 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ PacketFu.packet_classes.each do |pclass|
5
+ describe pclass, "peek format" do
6
+ it "will display sensible peek information" do
7
+ p = pclass.new
8
+ p.respond_to?(:peek).should be_true
9
+ p.peek.size.should be_<=(80), p.peek.inspect
10
+ p.peek.should match(/^[A-Z0-9?]../)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,90 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ unless %x{#{$0} --version} =~ /^2\.6/
5
+ puts "PacketFu needs rspec 2.6 or so."
6
+ exit 1
7
+ end
8
+
9
+ describe PacketFu, "version information" do
10
+ it "reports a version number" do
11
+ PacketFu::VERSION.should match /^1\.[0-9]\.[0-9]$/
12
+ end
13
+ its(:version) {should eq PacketFu::VERSION}
14
+
15
+ it "can compare version strings" do
16
+ PacketFu.binarize_version("1.2.3").should == 0x010203
17
+ PacketFu.binarize_version("3.0").should == 0x030000
18
+ PacketFu.at_least?("1.0").should be_true
19
+ PacketFu.at_least?("4.0").should be_false
20
+ PacketFu.older_than?("4.0").should be_true
21
+ PacketFu.newer_than?("1.0").should be_true
22
+ end
23
+
24
+ it "can handle .pre versions" do
25
+ PacketFu.binarize_version("1.7.6.pre").should == 0x010706
26
+ PacketFu.at_least?("0.9.0.pre").should be_true
27
+ end
28
+ end
29
+
30
+ describe PacketFu, "instance variables" do
31
+ it "should have a bunch of instance variables" do
32
+ PacketFu.instance_variable_get(:@byte_order).should == :little
33
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should_not be_nil
34
+ end
35
+ end
36
+
37
+ describe PacketFu, "pcaprub deps" do
38
+ it "should check for pcaprub" do
39
+ begin
40
+ has_pcap = false
41
+ require 'pcaprub'
42
+ has_pcap = true
43
+ rescue LoadError
44
+ end
45
+ if has_pcap
46
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should be_true
47
+ else
48
+ PacketFu.instance_variable_get(:@pcaprub_loaded).should be_false
49
+ end
50
+ end
51
+ end
52
+
53
+ describe PacketFu, "protocol requires" do
54
+ it "should have some protocols defined" do
55
+ PacketFu::EthPacket.should_not be_nil
56
+ PacketFu::IPPacket.should_not be_nil
57
+ PacketFu::TCPPacket.should_not be_nil
58
+ expect { PacketFu::FakePacket }.to raise_error
59
+ end
60
+ end
61
+
62
+ describe PacketFu, "packet class list management" do
63
+
64
+ before(:all) do
65
+ class PacketFu::FooPacket < PacketFu::Packet; end
66
+ class PacketFu::BarPacket < PacketFu::Packet; end
67
+ class PacketFu::PacketBaz; end
68
+ end
69
+
70
+ it "should allow packet class registration" do
71
+ PacketFu.add_packet_class(PacketFu::FooPacket).should be_kind_of Array
72
+ PacketFu.add_packet_class(PacketFu::BarPacket).should be_kind_of Array
73
+ end
74
+
75
+ its(:packet_classes) {should include(PacketFu::FooPacket)}
76
+
77
+ it "should disallow non-classes as packet classes" do
78
+ expect { PacketFu.add_packet_class("A String") }.to raise_error
79
+ end
80
+
81
+ its(:packet_prefixes) {should include("bar")}
82
+
83
+ # Don't really have much utility for this right now.
84
+ it "should allow packet class deregistration" do
85
+ PacketFu.remove_packet_class(PacketFu::BarPacket)
86
+ PacketFu.packet_prefixes.should_not include("bar")
87
+ PacketFu.add_packet_class(PacketFu::BarPacket)
88
+ end
89
+
90
+ end
data/test/ptest.rb ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib/")
3
+ require 'pcaprub'
4
+ require 'packetfu'
5
+ include PacketFu
6
+
7
+ if Process.euid.zero?
8
+ puts ">> Interface: " << Pcap.lookupdev
9
+ else
10
+ puts ">> No interface access"
11
+ end
12
+ puts ">> Version: " << PacketFu.version
13
+
14
+ # vim: nowrap sw=2 sts=0 ts=2 ff=unix ft=ruby
15
+
16
+
Binary file
data/test/sample.pcap ADDED
Binary file
data/test/sample2.pcap ADDED
Binary file
Binary file
@@ -0,0 +1,335 @@
1
+ $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), "..", "lib")
2
+ require 'packetfu'
3
+
4
+ describe StructFu, "mixin methods" do
5
+
6
+ before :each do
7
+ class StructClass
8
+ include StructFu
9
+ end
10
+ @sc = StructClass.new
11
+ end
12
+
13
+ it "should provide the basic StructFu methods" do
14
+ @sc.respond_to?(:sz).should be_true
15
+ @sc.respond_to?(:len).should be_true
16
+ @sc.respond_to?(:typecast).should be_true
17
+ @sc.respond_to?(:body=).should be_true
18
+ end
19
+ end
20
+
21
+ describe StructFu::Int, "basic Int class" do
22
+
23
+ before :each do
24
+ @int = StructFu::Int.new(8)
25
+ end
26
+
27
+ it "should have an initial state" do
28
+ new_int = StructFu::Int.new
29
+ new_int.value.should be_nil
30
+ new_int.endian.should be_nil
31
+ new_int.width.should be_nil
32
+ new_int.default.should == 0
33
+ end
34
+
35
+ it "should raise when to_s'ed directly" do
36
+ expect { @int.to_s}.to raise_error
37
+ end
38
+
39
+ it "should have a value of 8" do
40
+ @int.value.should == 8
41
+ @int.to_i.should == 8
42
+ @int.to_f.to_s.should == "8.0"
43
+ end
44
+
45
+ it "should read an integer" do
46
+ @int.read(7)
47
+ @int.to_i.should == 7
48
+ end
49
+
50
+ end
51
+
52
+ describe StructFu::Int8, "one byte value" do
53
+
54
+ before :each do
55
+ @int = StructFu::Int8.new(11)
56
+ end
57
+
58
+ it "should have an initial state" do
59
+ new_int = StructFu::Int8.new
60
+ new_int.value.should be_nil
61
+ new_int.endian.should be_nil
62
+ new_int.width.should == 1
63
+ new_int.default.should == 0
64
+ end
65
+
66
+ it "should print a one character packed string" do
67
+ @int.to_s.should == "\x0b"
68
+ end
69
+
70
+ it "should have a value of 11" do
71
+ @int.value.should == 11
72
+ @int.to_i.should == 11
73
+ @int.to_f.to_s.should == "11.0"
74
+ end
75
+
76
+ it "should reset with a new integer" do
77
+ @int.read(2)
78
+ @int.to_i.should == 2
79
+ @int.to_s.should == "\x02"
80
+ @int.read(254)
81
+ @int.to_i.should == 254
82
+ @int.to_s.should == "\xfe"
83
+ end
84
+
85
+ end
86
+
87
+ describe StructFu::Int16, "two byte value" do
88
+
89
+ before :each do
90
+ @int = StructFu::Int16.new(11)
91
+ end
92
+
93
+ it "should have an initial state" do
94
+ new_int = StructFu::Int16.new
95
+ new_int.value.should be_nil
96
+ new_int.endian.should == :big
97
+ new_int.width.should == 2
98
+ new_int.default.should == 0
99
+ end
100
+
101
+ it "should print a two character packed string" do
102
+ @int.to_s.should == "\x00\x0b"
103
+ end
104
+
105
+ it "should have a value of 11" do
106
+ @int.value.should == 11
107
+ @int.to_i.should == 11
108
+ @int.to_f.to_s.should == "11.0"
109
+ end
110
+
111
+ it "should reset with a new integer" do
112
+ @int.read(2)
113
+ @int.to_i.should == 2
114
+ @int.to_s.should == "\x00\x02"
115
+ @int.read(254)
116
+ @int.to_i.should == 254
117
+ @int.to_s.should == "\x00\xfe"
118
+ end
119
+
120
+ it "should be able to set endianness" do
121
+ int_be = StructFu::Int16.new(11,:big)
122
+ int_be.to_s.should == "\x00\x0b"
123
+ int_le = StructFu::Int16.new(11,:little)
124
+ int_le.to_s.should == "\x0b\x00"
125
+ end
126
+
127
+ it "should be able to switch endianness" do
128
+ @int.endian.should == :big
129
+ @int.to_s.should == "\x00\x0b"
130
+ @int.endian = :little
131
+ @int.endian.should == :little
132
+ @int.read(11)
133
+ @int.to_s.should == "\x0b\x00"
134
+ end
135
+
136
+ end
137
+
138
+ describe StructFu::Int16le, "2 byte little-endian value" do
139
+
140
+ before :each do
141
+ @int = StructFu::Int16le.new(11)
142
+ end
143
+
144
+ it "should behave pretty much like any other 16 bit int" do
145
+ @int.to_s.should == "\x0b\x00"
146
+ end
147
+
148
+ it "should raise when you try to change endianness" do
149
+ expect { @int.endian = :big }.to raise_error
150
+ expect { @int.endian = :little }.to raise_error
151
+ end
152
+
153
+ end
154
+
155
+ describe StructFu::Int16be, "2 byte big-endian value" do
156
+
157
+ before :each do
158
+ @int = StructFu::Int16be.new(11)
159
+ end
160
+
161
+ it "should behave pretty much like any other 16 bit int" do
162
+ @int.to_s.should == "\x00\x0b"
163
+ end
164
+
165
+ it "should raise when you try to change endianness" do
166
+ expect { @int.endian = :big }.to raise_error
167
+ expect { @int.endian = :little }.to raise_error
168
+ end
169
+
170
+ end
171
+
172
+ describe StructFu::Int32, "four byte value" do
173
+
174
+ before :each do
175
+ @int = StructFu::Int32.new(11)
176
+ end
177
+
178
+ it "should have an initial state" do
179
+ new_int = StructFu::Int32.new
180
+ new_int.value.should be_nil
181
+ new_int.endian.should == :big
182
+ new_int.width.should == 4
183
+ new_int.default.should == 0
184
+ end
185
+
186
+ it "should print a four character packed string" do
187
+ @int.to_s.should == "\x00\x00\x00\x0b"
188
+ end
189
+
190
+ it "should have a value of 11" do
191
+ @int.value.should == 11
192
+ @int.to_i.should == 11
193
+ @int.to_f.to_s.should == "11.0"
194
+ end
195
+
196
+ it "should reset with a new integer" do
197
+ @int.read(2)
198
+ @int.to_i.should == 2
199
+ @int.to_s.should == "\x00\x00\x00\x02"
200
+ @int.read(254)
201
+ @int.to_i.should == 254
202
+ @int.to_s.should == "\x00\x00\x00\xfe"
203
+ end
204
+
205
+ it "should be able to set endianness" do
206
+ int_be = StructFu::Int32.new(11,:big)
207
+ int_be.to_s.should == "\x00\x00\x00\x0b"
208
+ int_le = StructFu::Int32.new(11,:little)
209
+ int_le.to_s.should == "\x0b\x00\x00\x00"
210
+ end
211
+
212
+ it "should be able to switch endianness" do
213
+ @int.endian.should == :big
214
+ @int.to_s.should == "\x00\x00\x00\x0b"
215
+ @int.endian = :little
216
+ @int.endian.should == :little
217
+ @int.read(11)
218
+ @int.to_s.should == "\x0b\x00\x00\x00"
219
+ end
220
+
221
+ end
222
+
223
+ describe StructFu::Int32le, "4 byte little-endian value" do
224
+
225
+ before :each do
226
+ @int = StructFu::Int32le.new(11)
227
+ end
228
+
229
+ it "should behave pretty much like any other 32 bit int" do
230
+ @int.to_s.should == "\x0b\x00\x00\x00"
231
+ end
232
+
233
+ it "should raise when you try to change endianness" do
234
+ expect { @int.endian = :big }.to raise_error
235
+ expect { @int.endian = :little }.to raise_error
236
+ end
237
+
238
+ end
239
+
240
+ describe StructFu::Int32be, "4 byte big-endian value" do
241
+
242
+ before :each do
243
+ @int = StructFu::Int32be.new(11)
244
+ end
245
+
246
+ it "should behave pretty much like any other 32 bit int" do
247
+ @int.to_s.should == "\x00\x00\x00\x0b"
248
+ end
249
+
250
+ it "should raise when you try to change endianness" do
251
+ expect { @int.endian = :big }.to raise_error
252
+ expect { @int.endian = :little }.to raise_error
253
+ end
254
+
255
+ end
256
+
257
+ describe StructFu::String, "a sligtly more special String" do
258
+
259
+ before :each do
260
+ @str = StructFu::String.new("Oi, a string")
261
+ end
262
+
263
+ it "should behave pretty much like a string" do
264
+ @str.should be_kind_of(String)
265
+ end
266
+
267
+ it "should have a read method" do
268
+ @str.should respond_to(:read)
269
+ end
270
+
271
+ it "should read data like other StructFu things" do
272
+ @str.read("hello")
273
+ @str.should == "hello"
274
+ end
275
+
276
+ end
277
+
278
+ describe StructFu::IntString do
279
+
280
+ it "should be" do
281
+ StructFu::IntString.should be
282
+ end
283
+
284
+ it "should have a length and value" do
285
+ istr = StructFu::IntString.new("Avast!")
286
+ istr.to_s.should == "\x06Avast!"
287
+ end
288
+
289
+ it "should have a 16-bit length and a value" do
290
+ istr = StructFu::IntString.new("Avast!",StructFu::Int16)
291
+ istr.to_s.should == "\x00\x06Avast!"
292
+ end
293
+
294
+ it "should have a 32-bit length and a value" do
295
+ istr = StructFu::IntString.new("Avast!",StructFu::Int32)
296
+ istr.to_s.should == "\x00\x00\x00\x06Avast!"
297
+ end
298
+
299
+ before :each do
300
+ @istr = StructFu::IntString.new("Avast!",StructFu::Int32)
301
+ end
302
+
303
+ it "should report the correct length with a new string" do
304
+ @istr.to_s.should == "\x00\x00\x00\x06Avast!"
305
+ @istr.string = "Ahoy!"
306
+ @istr.to_s.should == "\x00\x00\x00\x05Ahoy!"
307
+ end
308
+
309
+ it "should report the correct length with a new string" do
310
+ @istr.string = "Ahoy!"
311
+ @istr.to_s.should == "\x00\x00\x00\x05Ahoy!"
312
+ end
313
+
314
+ it "should keep the old length with a new string" do
315
+ @istr[:string] = "Ahoy!"
316
+ @istr.to_s.should == "\x00\x00\x00\x06Ahoy!"
317
+ end
318
+
319
+ it "should allow for adjusting the length manually" do
320
+ @istr.len = 16
321
+ @istr.to_s.should == "\x00\x00\x00\x10Avast!"
322
+ end
323
+
324
+ it "should read in an expected string" do
325
+ data = "\x00\x00\x00\x09Yo ho ho!"
326
+ @istr.read(data)
327
+ @istr.to_s.should == data
328
+ end
329
+
330
+ it "should raise when a string is too short" do
331
+ data = "\x01A"
332
+ expect { @istr.read(data) }.to raise_error
333
+ end
334
+
335
+ end