bencodr 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +34 -0
- data/.document +5 -0
- data/.gitignore +25 -0
- data/LICENSE +20 -0
- data/README.rdoc +147 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +3 -0
- data/bencode_blatyo.gemspec +78 -0
- data/lib/bencodr/dictionary.rb +57 -0
- data/lib/bencodr/integer.rb +57 -0
- data/lib/bencodr/list.rb +55 -0
- data/lib/bencodr/parser.rb +113 -0
- data/lib/bencodr/string.rb +58 -0
- data/lib/bencodr.rb +56 -0
- data/spec/bencode_spec.rb +86 -0
- data/spec/bencodr/dictionary_spec.rb +79 -0
- data/spec/bencodr/integer_spec.rb +72 -0
- data/spec/bencodr/list_spec.rb +36 -0
- data/spec/bencodr/parser_spec.rb +176 -0
- data/spec/bencodr/string_spec.rb +73 -0
- data/spec/samples/bencode.rb.torrent +1 -0
- data/spec/samples/mini.bencode +1 -0
- data/spec/samples/python.torrent +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- metadata +106 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module BEncodr
|
6
|
+
module String
|
7
|
+
module Generic
|
8
|
+
module InstanceMethods
|
9
|
+
# Encodes object into a bencoded string. BEncoded strings are length-prefixed base ten followed by a colon and
|
10
|
+
# the string.
|
11
|
+
#
|
12
|
+
# :symbol.bencodr #=> "6:symbol"
|
13
|
+
#
|
14
|
+
# @return [::String] the bencoded string
|
15
|
+
def bencode
|
16
|
+
(respond_to?(:to_s) ? to_s : to_str).bencode
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Registers a class as an object that can be converted into a bencoded string. Class must have instance method to_s
|
22
|
+
# or to_str.
|
23
|
+
#
|
24
|
+
# class MyClass
|
25
|
+
# def to_s
|
26
|
+
# "string"
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# BEncode::String.register MyClass
|
31
|
+
# my_class = MyClass.new
|
32
|
+
# my_class.bencodr #=> "6:string"
|
33
|
+
#
|
34
|
+
# @param [Class#to_s, Class#to_str] type the class to add the bencodr instance method to
|
35
|
+
def self.register(type)
|
36
|
+
type.send :include, Generic::InstanceMethods
|
37
|
+
end
|
38
|
+
|
39
|
+
register Symbol
|
40
|
+
register URI::Generic
|
41
|
+
|
42
|
+
module String
|
43
|
+
module InstanceMethods
|
44
|
+
# Encodes a string into a bencoded string. BEncoded strings are length-prefixed base ten followed by a colon and
|
45
|
+
# the string.
|
46
|
+
#
|
47
|
+
# "string".bencodr #=> "6:string"
|
48
|
+
#
|
49
|
+
# @return [::String] the bencoded string
|
50
|
+
def bencode
|
51
|
+
[length, ':', self].join
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
::String.send :include, InstanceMethods
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/bencodr.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
path = File.expand_path(File.dirname(__FILE__)) + "/bencodr"
|
4
|
+
|
5
|
+
require path + "/string"
|
6
|
+
require path + "/integer"
|
7
|
+
require path + "/list"
|
8
|
+
require path + "/dictionary"
|
9
|
+
require path + "/parser"
|
10
|
+
|
11
|
+
module BEncodr
|
12
|
+
class BEncodeError < StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# This method decodes a bencoded string.
|
16
|
+
#
|
17
|
+
# BEncode.decode("6:string") #=> "string"
|
18
|
+
#
|
19
|
+
# @param [::String] string the bencoded string to decode
|
20
|
+
# @return [::String, ::Integer, ::Hash, ::Array] the decoded object
|
21
|
+
def decode(string)
|
22
|
+
scanner = StringScanner.new(string)
|
23
|
+
Parser.parse_object(scanner) or raise BEncodeError, "Invalid bencoding"
|
24
|
+
end
|
25
|
+
|
26
|
+
# This method decodes a bencoded file.
|
27
|
+
#
|
28
|
+
# BEncode.decode_file("simple.torrent") #=> "d8:announce32:http://www..."
|
29
|
+
#
|
30
|
+
# @param [::String] file the file to decode
|
31
|
+
# @return [::String, ::Integer, ::Hash, ::Array] the decoded object
|
32
|
+
def decode_file(file)
|
33
|
+
decode(File.open(file, 'rb') {|f| f.read})
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method encodes a bencoded object.
|
37
|
+
#
|
38
|
+
# BEncode.encode("string") #=> "6:string"
|
39
|
+
#
|
40
|
+
# @param [#bencodr] object the object to encode
|
41
|
+
# @return [::String] the bencoded object
|
42
|
+
def encode(object)
|
43
|
+
object.bencode
|
44
|
+
end
|
45
|
+
|
46
|
+
# This method encodes a bencoded object.
|
47
|
+
#
|
48
|
+
# BEncode.encode("string") #=> "6:string"
|
49
|
+
#
|
50
|
+
# @param [::String] file the file to write the bencoded object to
|
51
|
+
# @param [#bencodr] object the object to encode
|
52
|
+
def encode_file(file, object)
|
53
|
+
File.open(file, 'wb') {|f| f.write encode(object)}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe BEncodr do
|
7
|
+
describe "#decode" do
|
8
|
+
# Most of this is covered in other tests. Only difference is this accepts string instead of scanner.
|
9
|
+
it "should parse a bencoded string" do
|
10
|
+
BEncodr.decode("6:string").should == "string"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse a bencoded integer" do
|
14
|
+
BEncodr.decode("i4e").should == 4
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should parse a bencoded list" do
|
18
|
+
BEncodr.decode("l6:stringeeeee").should == ["string"]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse a bencoded dictionary containing a key value pair" do
|
22
|
+
BEncodr.decode("d6:stringi1ee").should == {"string" => 1}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should raise an error when the type is not recognized" do
|
26
|
+
lambda{BEncodr.decode("freak out!")}.should raise_error BEncodr::BEncodeError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#decode_file" do
|
31
|
+
it "should parse a bencoded file" do
|
32
|
+
dirname = File.dirname(__FILE__)
|
33
|
+
BEncodr.decode_file("#{dirname}/samples/mini.bencode").should == {"ba" => 3}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#encode" do
|
38
|
+
# Covered in other tests so only simple stuff here.
|
39
|
+
it "should bencodr an object" do
|
40
|
+
BEncodr.encode("string").should == "6:string"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#encode_file" do
|
45
|
+
context "when an object gets bencoded and written to a file" do
|
46
|
+
before :all do
|
47
|
+
@path = File.join(File.dirname(__FILE__), '..', 'tmp')
|
48
|
+
Dir.mkdir(@path) unless File.exists? @path
|
49
|
+
end
|
50
|
+
|
51
|
+
before :each do
|
52
|
+
@file = File.join(@path, 'test.bencodr')
|
53
|
+
@object = "string"
|
54
|
+
BEncodr.encode_file(@file, @object)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should actually write a file" do
|
58
|
+
File.exists?(@file).should be_true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should properly encode the file" do
|
62
|
+
BEncodr.decode_file(@file).should == @object
|
63
|
+
end
|
64
|
+
|
65
|
+
after :each do
|
66
|
+
File.delete(@file)
|
67
|
+
end
|
68
|
+
|
69
|
+
after :all do
|
70
|
+
Dir.delete(@path) if File.exists? @path
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should read a torrent with newlines as part of a string without raising an error" do
|
75
|
+
file = File.join(File.dirname(__FILE__), 'samples', 'python.torrent')
|
76
|
+
lambda{BEncodr.decode_file file}.should_not raise_error
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when parsing and then encoding" do
|
81
|
+
it "should be equal to the pre-parsed and encoded bencoded string" do
|
82
|
+
file = File.dirname(__FILE__) + "/samples/bencode.rb.torrent"
|
83
|
+
BEncodr.decode_file(file).bencode.should == File.open(file, "rb") {|f| f.read}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Hash do
|
7
|
+
describe "#bencodr" do
|
8
|
+
it "should encode an empty hash" do
|
9
|
+
{}.bencode.should == "de"
|
10
|
+
end
|
11
|
+
|
12
|
+
context "a key should always be encoded as a string" do
|
13
|
+
it "should encode a string key as a string" do
|
14
|
+
{"string" => "string"}.bencode.should == "d6:string6:stringe"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should encode a symbol key as a string" do
|
18
|
+
{:symbol => :symbol}.bencode.should == "d6:symbol6:symbole"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should encode a uri key as a string" do
|
22
|
+
uri = URI.parse("http://github.com/blatyo/bencode")
|
23
|
+
{uri => uri}.bencode.should == "d32:http://github.com/blatyo/bencode32:http://github.com/blatyo/bencodee"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should encode an integer key as a string" do
|
27
|
+
{1 => 1}.bencode.should == "d1:1i1ee"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should encode a float key as a string" do
|
31
|
+
{1.1 => 1.1}.bencode.should == "d3:1.1i1ee"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should encode a time key as a string" do
|
35
|
+
time = Time.utc(0)
|
36
|
+
{time => time}.bencode.should == "d23:2000-01-01 00:00:00 UTCi946684800ee"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should encode an array key as a string" do
|
40
|
+
array = (1..4).to_a
|
41
|
+
{array => array}.bencode.should == "d12:[1, 2, 3, 4]li1ei2ei3ei4eee"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should encode a hash key as a string" do
|
45
|
+
{{} => {}}.bencode.should == "d2:{}dee"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should encode keys in sorted (as raw strings) order" do
|
50
|
+
{:a => 1, "A" => 1, 1=> 1}.bencode.should == "d1:1i1e1:Ai1e1:ai1ee"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe BEncodr::Dictionary do
|
56
|
+
describe "#register" do
|
57
|
+
context "once an object has been registered as a BEncode dictionary" do
|
58
|
+
before :all do
|
59
|
+
klass = Class.new do
|
60
|
+
def to_h
|
61
|
+
{:a => "a", :b => "b"}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
BEncodr::Dictionary.register klass
|
65
|
+
@instance = klass.new
|
66
|
+
end
|
67
|
+
|
68
|
+
context "an instance of that object" do
|
69
|
+
it "should respond to bencodr" do
|
70
|
+
@instance.should respond_to :bencode
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should encode to a bencoded dictionary" do
|
74
|
+
@instance.bencode.should == "d1:a1:a1:b1:be"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Integer do
|
7
|
+
describe "#bencodr" do
|
8
|
+
it "should encode a positive integer" do
|
9
|
+
1.bencode.should == "i1e"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should encode a negative integer" do
|
13
|
+
-1.bencode.should == "i-1e"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should encode a positive big integer" do
|
17
|
+
10_000_000_000.bencode.should == "i10000000000e"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should encode a negative big integer" do
|
21
|
+
-10_000_000_000.bencode.should == "i-10000000000e"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe Numeric do
|
27
|
+
describe "#bencodr" do
|
28
|
+
it "should encode a positive float with precision loss" do
|
29
|
+
1.1.bencode.should == "i1e"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should encode a negative float with precision loss" do
|
33
|
+
-1.1.bencode.should == "i-1e"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should encode an positive exponential float" do
|
37
|
+
1e10.bencode.should == "i10000000000e"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should encode an negative exponential float" do
|
41
|
+
-1e10.bencode.should == "i-10000000000e"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe Time do
|
47
|
+
describe "#bencodr" do
|
48
|
+
it "should encode to bencoding" do
|
49
|
+
Time.at(4).bencode.should == "i4e"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe BEncodr::Integer do
|
55
|
+
describe "#register" do
|
56
|
+
context "once an object has been registered as a BEncode integer" do
|
57
|
+
before :all do
|
58
|
+
BEncodr::Integer.register NilClass
|
59
|
+
end
|
60
|
+
|
61
|
+
context "an instance of that object" do
|
62
|
+
it "should respond to bencodr" do
|
63
|
+
nil.should respond_to :bencode
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should encode to a bencoded integer" do
|
67
|
+
nil.bencode.should == "i0e"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Array do
|
7
|
+
describe "#bencodr" do
|
8
|
+
it "should encode an empty array" do
|
9
|
+
[].bencode.should == "le"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should encode an array filled with bencodable objects" do
|
13
|
+
[:e, "a", 1, Time.at(11)].bencode.should == "l1:e1:ai1ei11ee"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe BEncodr::List do
|
19
|
+
describe "#register" do
|
20
|
+
context "once an object has been registered as a BEncode list" do
|
21
|
+
before :all do
|
22
|
+
BEncodr::List.register Range
|
23
|
+
end
|
24
|
+
|
25
|
+
context "an instance of that object" do
|
26
|
+
it "should respond to bencodr" do
|
27
|
+
(1..2).should respond_to :bencode
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should encode to a bencoded list" do
|
31
|
+
(1..2).bencode.should == "li1ei2ee"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
|
5
|
+
describe BEncodr::Parser do
|
6
|
+
describe "#parse_object" do
|
7
|
+
# Most of this functionality is covered with other tests. So minimal stuff here.
|
8
|
+
it "should parse a bencoded string" do
|
9
|
+
scanner = StringScanner.new("6:string")
|
10
|
+
BEncodr::Parser.parse_object(scanner).should == "string"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse a bencoded integer" do
|
14
|
+
scanner = StringScanner.new("i4e")
|
15
|
+
BEncodr::Parser.parse_object(scanner).should == 4
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse a bencoded list" do
|
19
|
+
scanner = StringScanner.new("l6:stringeeeee")
|
20
|
+
BEncodr::Parser.parse_object(scanner).should == ["string"]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should parse a bencoded dictionary containing a key value pair" do
|
24
|
+
scanner = StringScanner.new("d6:stringi1ee")
|
25
|
+
BEncodr::Parser.parse_object(scanner).should == {"string" => 1}
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return nil when the type is not recognized" do
|
29
|
+
scanner = StringScanner.new("freak out!")
|
30
|
+
BEncodr::Parser.parse_object(scanner).should == nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#parse_stirng" do
|
35
|
+
it "should parse a bencoded string" do
|
36
|
+
scanner = StringScanner.new("6:string")
|
37
|
+
BEncodr::Parser.parse_string(scanner).should == "string"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should parse a zero length bencoded string" do
|
41
|
+
scanner = StringScanner.new("0:")
|
42
|
+
BEncodr::Parser.parse_string(scanner).should == ""
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should raise an error if the length is invalid" do
|
46
|
+
scanner = StringScanner.new("fail:")
|
47
|
+
lambda {BEncodr::Parser.parse_string(scanner)}.should raise_error BEncodr::BEncodeError
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should raise an error if length is too long" do
|
51
|
+
scanner = StringScanner.new("3:a")
|
52
|
+
lambda {BEncodr::Parser.parse_string(scanner)}.should raise_error BEncodr::BEncodeError
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise an error if the colon is missing" do
|
56
|
+
scanner = StringScanner.new("3aaa")
|
57
|
+
lambda {BEncodr::Parser.parse_string(scanner)}.should raise_error BEncodr::BEncodeError
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#parse_integer" do
|
62
|
+
it "should parse a bencoded integer" do
|
63
|
+
scanner = StringScanner.new("i4e")
|
64
|
+
BEncodr::Parser.parse_integer(scanner).should == 4
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should raise an error if there is no starting i" do
|
68
|
+
scanner = StringScanner.new("4e")
|
69
|
+
lambda{BEncodr::Parser.parse_integer(scanner)}.should raise_error BEncodr::BEncodeError
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise an error if there is no integer" do
|
73
|
+
scanner = StringScanner.new("ie")
|
74
|
+
lambda{BEncodr::Parser.parse_integer(scanner)}.should raise_error BEncodr::BEncodeError
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise an error if there is no closing e" do
|
78
|
+
scanner = StringScanner.new("i4")
|
79
|
+
lambda{BEncodr::Parser.parse_integer(scanner)}.should raise_error BEncodr::BEncodeError
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#parse_list" do
|
84
|
+
it "should parse an empty bencoded list" do
|
85
|
+
scanner = StringScanner.new("le")
|
86
|
+
BEncodr::Parser.parse_list(scanner).should == []
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should parse a bencoded list containing a string" do
|
90
|
+
scanner = StringScanner.new("l6:stringeeeee")
|
91
|
+
BEncodr::Parser.parse_list(scanner).should == ["string"]
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should parse a bencoded list containing more than one string" do
|
95
|
+
scanner = StringScanner.new("l6:string6:stringe")
|
96
|
+
BEncodr::Parser.parse_list(scanner).should == ["string", "string"]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should parse a bencoded list containing an integer" do
|
100
|
+
scanner = StringScanner.new("li1ee")
|
101
|
+
BEncodr::Parser.parse_list(scanner).should == [1]
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should parse a bencoded list containing more than one integer" do
|
105
|
+
scanner = StringScanner.new("li1ei2ee")
|
106
|
+
BEncodr::Parser.parse_list(scanner).should == [1, 2]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should parse a bencoded list containing a list" do
|
110
|
+
scanner = StringScanner.new("llee")
|
111
|
+
BEncodr::Parser.parse_list(scanner).should == [[]]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should parse a bencoded list containing more than one list" do
|
115
|
+
scanner = StringScanner.new("llelee")
|
116
|
+
BEncodr::Parser.parse_list(scanner).should == [[], []]
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should parse a bencoded list containing a dictionary" do
|
120
|
+
scanner = StringScanner.new("ldee")
|
121
|
+
BEncodr::Parser.parse_list(scanner).should == [{}]
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should parse a bencoded list containing more than one dictionary" do
|
125
|
+
scanner = StringScanner.new("ldedee")
|
126
|
+
BEncodr::Parser.parse_list(scanner).should == [{}, {}]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should raise an error if there is no starting l" do
|
130
|
+
scanner = StringScanner.new("e")
|
131
|
+
lambda{BEncodr::Parser.parse_list(scanner)}.should raise_error BEncodr::BEncodeError
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should raise an error if there is no closing e" do
|
135
|
+
scanner = StringScanner.new("l")
|
136
|
+
lambda{BEncodr::Parser.parse_list(scanner)}.should raise_error BEncodr::BEncodeError
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#parse_dictionary" do
|
141
|
+
it "should parse an empty bencoded dictionary" do
|
142
|
+
scanner = StringScanner.new("de")
|
143
|
+
BEncodr::Parser.parse_dictionary(scanner).should == {}
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should parse a bencoded dictionary containing a key value pair" do
|
147
|
+
scanner = StringScanner.new("d6:stringi1ee")
|
148
|
+
BEncodr::Parser.parse_dictionary(scanner).should == {"string" => 1}
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should parse a bencoded dictionary containing more than one key value pair" do
|
152
|
+
scanner = StringScanner.new("d7:anotherle6:stringi1ee")
|
153
|
+
BEncodr::Parser.parse_dictionary(scanner).should == {"string" => 1, "another" => []}
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should raise an error if there is no starting d" do
|
157
|
+
scanner = StringScanner.new("e")
|
158
|
+
lambda{BEncodr::Parser.parse_dictionary(scanner)}.should raise_error BEncodr::BEncodeError
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should raise an error if the key is not a string" do
|
162
|
+
scanner = StringScanner.new("di1ei1ee")
|
163
|
+
lambda{BEncodr::Parser.parse_dictionary(scanner)}.should raise_error BEncodr::BEncodeError
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should raise an error if there is no closing e" do
|
167
|
+
scanner = StringScanner.new("d")
|
168
|
+
lambda{BEncodr::Parser.parse_dictionary(scanner)}.should raise_error BEncodr::BEncodeError
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should raise an error if there is a key with no value" do
|
172
|
+
scanner = StringScanner.new("d1:ae")
|
173
|
+
lambda{BEncodr::Parser.parse_dictionary(scanner)}.should raise_error BEncodr::BEncodeError
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "spec"
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe String do
|
7
|
+
describe "#bencodr" do
|
8
|
+
it "should encode a string" do
|
9
|
+
"string".bencode.should == "6:string"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should encode a zero length string" do
|
13
|
+
"".bencode.should == "0:"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe Symbol do
|
19
|
+
describe "#bencodr" do
|
20
|
+
it "should encode a symbol" do
|
21
|
+
:symbol.bencode.should == "6:symbol"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe URI::Generic do
|
27
|
+
describe "#bencodr" do
|
28
|
+
it "should encode a http uri" do
|
29
|
+
uri = URI.parse("http://github.com/blatyo/bencodr")
|
30
|
+
uri.bencode.should == "32:http://github.com/blatyo/bencodr"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should encode a https uri" do
|
34
|
+
uri = URI.parse("https://github.com/blatyo/bencodr")
|
35
|
+
uri.bencode.should == "33:https://github.com/blatyo/bencodr"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should encode a ftp uri" do
|
39
|
+
uri = URI.parse("ftp://github.com/blatyo/bencodr")
|
40
|
+
uri.bencode.should == "31:ftp://github.com/blatyo/bencodr"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should encode a ldap uri" do
|
44
|
+
uri = URI.parse("ldap://github.com/blatyo/bencodr")
|
45
|
+
uri.bencode.should == "32:ldap://github.com/blatyo/bencodr"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should encode a mailto uri" do
|
49
|
+
uri = URI.parse("mailto:sudo@sudoers.su")
|
50
|
+
uri.bencode.should == "22:mailto:sudo@sudoers.su"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe BEncodr::String do
|
56
|
+
describe "#register" do
|
57
|
+
context "once an object has been registered as a BEncode string" do
|
58
|
+
before :all do
|
59
|
+
BEncodr::String.register Range
|
60
|
+
end
|
61
|
+
|
62
|
+
context "an instance of that object" do
|
63
|
+
it "should respond to bencodr" do
|
64
|
+
(1..2).should respond_to :bencode
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should encode to a bencoded string" do
|
68
|
+
(1..2).bencode.should == "4:1..2"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
d8:announce42:http://tracker.openbittorrent.com/announce13:announce-listll42:http://tracker.openbittorrent.com/announce44:udp://tracker.openbittorrent.com:80/announceee7:comment28:Best bencoding library ever!10:created by13:uTorrent/185013:creation datei1264866817e8:encoding5:UTF-84:infod6:lengthi526e4:name10:bencode.rb12:piece lengthi65536e6:pieces20:�WiP�2�n�����U��W&��ee
|
@@ -0,0 +1 @@
|
|
1
|
+
d2:bai3ee
|
Binary file
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED