packetfu 1.1.2 → 1.1.3

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 (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