krypt 0.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/LICENSE +20 -0
- data/README.md +82 -0
- data/lib/krypt.rb +49 -0
- data/lib/krypt/asn1.rb +3 -0
- data/lib/krypt/asn1/common.rb +96 -0
- data/lib/krypt/asn1/template.rb +257 -0
- data/lib/krypt/codec.rb +57 -0
- data/lib/krypt/codec/base64.rb +140 -0
- data/lib/krypt/codec/base_codec.rb +36 -0
- data/lib/krypt/codec/hex.rb +122 -0
- data/lib/krypt/digest.rb +112 -0
- data/lib/krypt/hmac.rb +69 -0
- data/lib/krypt/pkcs5.rb +1 -0
- data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
- data/lib/krypt/provider.rb +35 -0
- data/lib/krypt/x509.rb +3 -0
- data/lib/krypt/x509/certificate.rb +36 -0
- data/lib/krypt/x509/common.rb +41 -0
- data/lib/krypt/x509/crl.rb +33 -0
- data/lib/krypt_missing.rb +32 -0
- data/spec/krypt-core/MEMO.txt +85 -0
- data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
- data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
- data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
- data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
- data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
- data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
- data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
- data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
- data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
- data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
- data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
- data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
- data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
- data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
- data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
- data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
- data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
- data/spec/krypt-core/asn1/resources.rb +53 -0
- data/spec/krypt-core/base64/base64_spec.rb +97 -0
- data/spec/krypt-core/digest/digest_spec.rb +707 -0
- data/spec/krypt-core/hex/hex_spec.rb +102 -0
- data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
- data/spec/krypt-core/resources.rb +1 -0
- data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
- data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
- data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
- data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
- data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
- data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
- data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
- data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
- data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
- data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
- data/spec/krypt/codec/identity_shared.rb +119 -0
- data/spec/krypt/hmac/hmac_spec.rb +311 -0
- data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
- data/spec/krypt/provider/provider_spec.rb +83 -0
- data/spec/res/ca-bundle.crt +11758 -0
- data/spec/res/certificate.cer +0 -0
- data/spec/res/certificate.pem +20 -0
- data/spec/res/multiple_certs.pem +60 -0
- data/spec/resources.rb +66 -0
- data/test/helper.rb +8 -0
- data/test/res/certificate.cer +0 -0
- data/test/resources.rb +48 -0
- data/test/scratch.rb +28 -0
- data/test/test_krypt_asn1.rb +119 -0
- data/test/test_krypt_parser.rb +331 -0
- metadata +134 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe Krypt::Base64::Decoder do
|
6
|
+
|
7
|
+
let(:klass) { Krypt::Base64::Decoder }
|
8
|
+
|
9
|
+
def write_string(s)
|
10
|
+
io = StringIO.new
|
11
|
+
b64 = klass.new(io)
|
12
|
+
b64 << s
|
13
|
+
b64.close
|
14
|
+
io.string
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_string(s)
|
18
|
+
io = StringIO.new(s)
|
19
|
+
b64 = klass.new(io)
|
20
|
+
begin
|
21
|
+
b64.read
|
22
|
+
ensure
|
23
|
+
b64.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "new" do
|
28
|
+
it "mandates a single parameter, the underlying IO" do
|
29
|
+
klass.new(StringIO.new).should be_an_instance_of klass
|
30
|
+
end
|
31
|
+
|
32
|
+
context "takes a block after whose execution the IO is closed" do
|
33
|
+
specify "successful execution of the block" do
|
34
|
+
io = StringIO.new
|
35
|
+
klass.new(io) do |b64|
|
36
|
+
b64 << "Zg=="
|
37
|
+
end
|
38
|
+
io.closed?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "failed execution of the block" do
|
42
|
+
io = StringIO.new
|
43
|
+
begin
|
44
|
+
klass.new(io) do |b64|
|
45
|
+
raise RuntimeError.new
|
46
|
+
end
|
47
|
+
rescue RuntimeError
|
48
|
+
io.closed?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
shared_examples_for "RFC 4648 Base64 decode" do |meth|
|
55
|
+
context "RFC 4648 test vectors" do
|
56
|
+
specify "empty string" do
|
57
|
+
send(meth, "").should == ""
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "f" do
|
61
|
+
send(meth, "Zg==").should == "f"
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "fo" do
|
65
|
+
send(meth, "Zm8=").should == "fo"
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "foo" do
|
69
|
+
send(meth, "Zm9v").should == "foo"
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "foob" do
|
73
|
+
send(meth, "Zm9vYg==").should == "foob"
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "fooba" do
|
77
|
+
send(meth, "Zm9vYmE=").should == "fooba"
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "foobar" do
|
81
|
+
send(meth, "Zm9vYmFy").should == "foobar"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#read" do
|
87
|
+
it_behaves_like "RFC 4648 Base64 decode", :read_string
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#write" do
|
91
|
+
it_behaves_like "RFC 4648 Base64 decode", :write_string
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe Krypt::Base64::Encoder do
|
6
|
+
|
7
|
+
let(:klass) { Krypt::Base64::Encoder }
|
8
|
+
|
9
|
+
def write_string(s)
|
10
|
+
io = StringIO.new
|
11
|
+
b64 = klass.new(io)
|
12
|
+
b64 << s
|
13
|
+
b64.close
|
14
|
+
io.string
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_string(s)
|
18
|
+
io = StringIO.new(s)
|
19
|
+
b64 = klass.new(io)
|
20
|
+
begin
|
21
|
+
b64.read
|
22
|
+
ensure
|
23
|
+
b64.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "new" do
|
28
|
+
it "mandates a single parameter, the underlying IO" do
|
29
|
+
klass.new(StringIO.new).should be_an_instance_of klass
|
30
|
+
end
|
31
|
+
|
32
|
+
context "takes a block after whose execution the IO is closed" do
|
33
|
+
specify "successful execution of the block" do
|
34
|
+
io = StringIO.new
|
35
|
+
klass.new(io) do |b64|
|
36
|
+
b64 << "test"
|
37
|
+
end
|
38
|
+
io.closed?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "failed execution of the block" do
|
42
|
+
io = StringIO.new
|
43
|
+
begin
|
44
|
+
klass.new(io) do |b64|
|
45
|
+
raise RuntimeError.new
|
46
|
+
end
|
47
|
+
rescue RuntimeError
|
48
|
+
io.closed?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
shared_examples_for "RFC 4648 Base64 encode" do |meth|
|
55
|
+
context "RFC 4648 test vectors" do
|
56
|
+
specify "empty string" do
|
57
|
+
send(meth, "").should == ""
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "f" do
|
61
|
+
send(meth, "f").should == "Zg=="
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "fo" do
|
65
|
+
send(meth, "fo").should == "Zm8="
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "foo" do
|
69
|
+
send(meth, "foo").should == "Zm9v"
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "foob" do
|
73
|
+
send(meth, "foob").should == "Zm9vYg=="
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "fooba" do
|
77
|
+
send(meth, "fooba").should == "Zm9vYmE="
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "foobar" do
|
81
|
+
send(meth, "foobar").should == "Zm9vYmFy"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#read" do
|
87
|
+
it_behaves_like "RFC 4648 Base64 encode", :read_string
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#write" do
|
91
|
+
it_behaves_like "RFC 4648 Base64 encode", :write_string
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe "Krypt::Base64 integration" do
|
6
|
+
|
7
|
+
let(:dec) { Krypt::Base64::Decoder }
|
8
|
+
let(:enc) { Krypt::Base64::Encoder }
|
9
|
+
|
10
|
+
require_relative 'identity_shared'
|
11
|
+
|
12
|
+
describe "Encoder and Decoder stacked on top of each other" do
|
13
|
+
it_behaves_like "Identity codec", Krypt::Base64::Encoder, Krypt::Base64::Decoder
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe Krypt::Hex::Decoder do
|
6
|
+
|
7
|
+
let(:klass) { Krypt::Hex::Decoder }
|
8
|
+
|
9
|
+
def write_string(s)
|
10
|
+
io = StringIO.new
|
11
|
+
hex = klass.new(io)
|
12
|
+
hex << s
|
13
|
+
hex.close
|
14
|
+
io.string
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_string(s)
|
18
|
+
io = StringIO.new(s)
|
19
|
+
hex = klass.new(io)
|
20
|
+
begin
|
21
|
+
hex.read
|
22
|
+
ensure
|
23
|
+
hex.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "new" do
|
28
|
+
it "mandates a single parameter, the underlying IO" do
|
29
|
+
klass.new(StringIO.new).should be_an_instance_of klass
|
30
|
+
end
|
31
|
+
|
32
|
+
context "takes a block after whose execution the IO is closed" do
|
33
|
+
specify "successful execution of the block" do
|
34
|
+
io = StringIO.new
|
35
|
+
klass.new(io) do |hex|
|
36
|
+
hex << "42"
|
37
|
+
end
|
38
|
+
io.closed?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "failed execution of the block" do
|
42
|
+
io = StringIO.new
|
43
|
+
begin
|
44
|
+
klass.new(io) do |hex|
|
45
|
+
raise RuntimeError.new
|
46
|
+
end
|
47
|
+
rescue RuntimeError
|
48
|
+
io.closed?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
shared_examples_for "RFC 4648 hex decode" do |meth|
|
55
|
+
context "RFC 4648 test vectors" do
|
56
|
+
specify "empty string" do
|
57
|
+
send(meth, "").should == ""
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "f" do
|
61
|
+
send(meth, "66").should == "f"
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "fo" do
|
65
|
+
send(meth, "666f").should == "fo"
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "foo" do
|
69
|
+
send(meth, "666f6f").should == "foo"
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "foob" do
|
73
|
+
send(meth, "666f6f62").should == "foob"
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "fooba" do
|
77
|
+
send(meth, "666f6f6261").should == "fooba"
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "foobar" do
|
81
|
+
send(meth, "666f6f626172").should == "foobar"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#read" do
|
87
|
+
it_behaves_like "RFC 4648 hex decode", :read_string
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#write" do
|
91
|
+
it_behaves_like "RFC 4648 hex decode", :write_string
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe Krypt::Hex::Encoder do
|
6
|
+
|
7
|
+
let(:klass) { Krypt::Hex::Encoder }
|
8
|
+
|
9
|
+
def write_string(s)
|
10
|
+
io = StringIO.new
|
11
|
+
hex = klass.new(io)
|
12
|
+
hex << s
|
13
|
+
hex.close
|
14
|
+
io.string
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_string(s)
|
18
|
+
io = StringIO.new(s)
|
19
|
+
hex = klass.new(io)
|
20
|
+
begin
|
21
|
+
hex.read
|
22
|
+
ensure
|
23
|
+
hex.close
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "new" do
|
28
|
+
it "mandates a single parameter, the underlying IO" do
|
29
|
+
klass.new(StringIO.new).should be_an_instance_of klass
|
30
|
+
end
|
31
|
+
|
32
|
+
context "takes a block after whose execution the IO is closed" do
|
33
|
+
specify "successful execution of the block" do
|
34
|
+
io = StringIO.new
|
35
|
+
klass.new(io) do |hex|
|
36
|
+
hex << "test"
|
37
|
+
end
|
38
|
+
io.closed?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "failed execution of the block" do
|
42
|
+
io = StringIO.new
|
43
|
+
begin
|
44
|
+
klass.new(io) do |hex|
|
45
|
+
raise RuntimeError.new
|
46
|
+
end
|
47
|
+
rescue RuntimeError
|
48
|
+
io.closed?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
shared_examples_for "RFC 4648 hex encode" do |meth|
|
55
|
+
context "RFC 4648 test vectors" do
|
56
|
+
specify "empty string" do
|
57
|
+
send(meth, "").should == ""
|
58
|
+
end
|
59
|
+
|
60
|
+
specify "f" do
|
61
|
+
send(meth, "f").should == "66"
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "fo" do
|
65
|
+
send(meth, "fo").should == "666f"
|
66
|
+
end
|
67
|
+
|
68
|
+
specify "foo" do
|
69
|
+
send(meth, "foo").should == "666f6f"
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "foob" do
|
73
|
+
send(meth, "foob").should == "666f6f62"
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "fooba" do
|
77
|
+
send(meth, "fooba").should == "666f6f6261"
|
78
|
+
end
|
79
|
+
|
80
|
+
specify "foobar" do
|
81
|
+
send(meth, "foobar").should == "666f6f626172"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#read" do
|
87
|
+
it_behaves_like "RFC 4648 hex encode", :read_string
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#write" do
|
91
|
+
it_behaves_like "RFC 4648 hex encode", :write_string
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
describe "Krypt::Hex integration" do
|
6
|
+
|
7
|
+
let(:dec) { Krypt::Hex::Decoder }
|
8
|
+
let(:enc) { Krypt::Hex::Encoder }
|
9
|
+
|
10
|
+
require_relative 'identity_shared'
|
11
|
+
|
12
|
+
describe "Encoder and Decoder stacked on top of each other" do
|
13
|
+
it_behaves_like "Identity codec", Krypt::Hex::Encoder, Krypt::Hex::Decoder
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
shared_examples_for "Identity codec" do |encoder, decoder|
|
2
|
+
|
3
|
+
let(:plain) { "test" * 1000 }
|
4
|
+
let(:encoded) do
|
5
|
+
io = StringIO.new
|
6
|
+
enc = encoder.new(io)
|
7
|
+
enc << ("test" * 1000)
|
8
|
+
enc.close
|
9
|
+
io.string
|
10
|
+
end
|
11
|
+
|
12
|
+
context "read_encoded" do
|
13
|
+
subject do
|
14
|
+
io = StringIO.new(encoded)
|
15
|
+
codec = encoder.new(decoder.new(io))
|
16
|
+
result = ""
|
17
|
+
while (c = codec.read(chunk_size))
|
18
|
+
result << c
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
context "single byte" do
|
24
|
+
let(:chunk_size) { 1 }
|
25
|
+
it { subject.should == encoded }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "chunks of 64" do
|
29
|
+
let(:chunk_size) { 64 }
|
30
|
+
it { subject.should == encoded }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "chunks of 3" do
|
34
|
+
let(:chunk_size) { 3 }
|
35
|
+
it { subject.should == encoded }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "read_plain" do
|
40
|
+
subject do
|
41
|
+
io = StringIO.new(plain)
|
42
|
+
codec = decoder.new(encoder.new(io))
|
43
|
+
result = ""
|
44
|
+
while (c = codec.read(chunk_size))
|
45
|
+
result << c
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
context "single byte" do
|
51
|
+
let(:chunk_size) { 1 }
|
52
|
+
it { subject.should == plain }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "chunks of 64" do
|
56
|
+
let(:chunk_size) { 64 }
|
57
|
+
it { subject.should == plain }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "chunks of 3" do
|
61
|
+
let(:chunk_size) { 3 }
|
62
|
+
it { subject.should == plain }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "write_encoded" do
|
67
|
+
subject do
|
68
|
+
io = StringIO.new
|
69
|
+
codec = dec.new(enc.new(io))
|
70
|
+
0.step(encoded.size, chunk_size) do |i|
|
71
|
+
codec << encoded.slice(i, chunk_size)
|
72
|
+
end
|
73
|
+
codec.close
|
74
|
+
io.string
|
75
|
+
end
|
76
|
+
|
77
|
+
context "single byte" do
|
78
|
+
let(:chunk_size) { 1 }
|
79
|
+
it { subject.should == encoded }
|
80
|
+
end
|
81
|
+
|
82
|
+
context "chunks of 64" do
|
83
|
+
let(:chunk_size) { 64 }
|
84
|
+
it { subject.should == encoded }
|
85
|
+
end
|
86
|
+
|
87
|
+
context "chunks of 3" do
|
88
|
+
let(:chunk_size) { 3 }
|
89
|
+
it { subject.should == encoded }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "write_plain" do
|
94
|
+
subject do
|
95
|
+
io = StringIO.new
|
96
|
+
codec = enc.new(dec.new(io))
|
97
|
+
0.step(plain.size, chunk_size) do |i|
|
98
|
+
codec << plain.slice(i, chunk_size)
|
99
|
+
end
|
100
|
+
codec.close
|
101
|
+
io.string
|
102
|
+
end
|
103
|
+
|
104
|
+
context "single byte" do
|
105
|
+
let(:chunk_size) { 1 }
|
106
|
+
it { subject.should == plain }
|
107
|
+
end
|
108
|
+
|
109
|
+
context "chunks of 64" do
|
110
|
+
let(:chunk_size) { 64 }
|
111
|
+
it { subject.should == plain }
|
112
|
+
end
|
113
|
+
|
114
|
+
context "chunks of 3" do
|
115
|
+
let(:chunk_size) { 3 }
|
116
|
+
it { subject.should == plain }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|