bencodr 1.0.1
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/.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