File: base64_spec.cr

package info (click to toggle)
crystal 1.14.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 24,384 kB
  • sloc: javascript: 6,400; sh: 695; makefile: 269; ansic: 121; python: 105; cpp: 77; xml: 32
file content (197 lines) | stat: -rw-r--r-- 6,956 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
require "spec"
require "base64"
require "crystal/digest/md5"
require "spec/helpers/string"

# rearrange parameters for `assert_prints`
{% for method in %w(encode strict_encode urlsafe_encode) %}
  private def base64_{{ method.id }}(io : IO, data, *args)
    Base64.{{ method.id }}(data, io, *args)
  end

  private def base64_{{ method.id }}(data, *args)
    Base64.{{ method.id }}(data, *args)
  end
{% end %}

describe "Base64" do
  context "simple test" do
    eqs = {"" => "", "a" => "YQ==\n", "ab" => "YWI=\n", "abc" => "YWJj\n",
           "abcd" => "YWJjZA==\n", "abcde" => "YWJjZGU=\n", "abcdef" => "YWJjZGVm\n",
           "abcdefg" => "YWJjZGVmZw==\n"}
    eqs.each do |a, b|
      it "encode #{a.inspect} to #{b.inspect}" do
        assert_prints base64_encode(a), b
      end
      it "decode from #{b.inspect} to #{a.inspect}" do
        Base64.decode(b).should eq(a.to_slice)
        Base64.decode_string(b).should eq(a)
      end
    end
  end

  context "\n in multiple places" do
    eqs = {"abcd" => "YWJj\nZA==\n", "abcde" => "YWJj\nZGU=\n", "abcdef" => "YWJj\nZGVm\n",
           "abcdefg" => "YWJj\nZGVmZw==\n", "abcdefg" => "YWJj\nZGVm\nZw==\n",
    }
    eqs.each do |a, b|
      it "decode from #{b.inspect} to #{a.inspect}" do
        Base64.decode(b).should eq(a.to_slice)
        Base64.decode_string(b).should eq(a)
      end
    end
  end

  it "encodes byte slice" do
    slice = Bytes.new(5) { 1_u8 }
    assert_prints base64_encode(slice), "AQEBAQE=\n"
    assert_prints base64_strict_encode(slice), "AQEBAQE="
  end

  it "encodes empty slice" do
    slice = Bytes.empty
    assert_prints base64_encode(slice), ""
    assert_prints base64_strict_encode(slice), ""
  end

  it "encodes static array" do
    array = uninitialized StaticArray(UInt8, 5)
    (0...5).each { |i| array[i] = 1_u8 }
    assert_prints base64_encode(array), "AQEBAQE=\n"
    assert_prints base64_strict_encode(array), "AQEBAQE="
  end

  describe "base" do
    eqs = {"Send reinforcements"                                                    => "U2VuZCByZWluZm9yY2VtZW50cw==\n",
           "Now is the time for all good coders\nto learn Crystal"                  => "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g\nQ3J5c3RhbA==\n",
           "This is line one\nThis is line two\nThis is line three\nAnd so on...\n" => "VGhpcyBpcyBsaW5lIG9uZQpUaGlzIGlzIGxpbmUgdHdvClRoaXMgaXMgbGlu\nZSB0aHJlZQpBbmQgc28gb24uLi4K\n",
           "hahah⊙ⓧ⊙"                                                               => "aGFoYWjiipnik6fiipk=\n"}
    eqs.each do |a, b|
      it "encode #{a.inspect} to #{b.inspect}" do
        assert_prints base64_encode(a), b
      end
      it "decode from #{b.inspect} to #{a.inspect}" do
        Base64.decode(b).should eq(a.to_slice)
        Base64.decode_string(b).should eq(a)
      end
    end

    it "decode from strict form" do
      Base64.decode_string("Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA==").should eq(
        "Now is the time for all good coders\nto learn Crystal")
    end

    it "encode to stream returns number of written characters" do
      io = IO::Memory.new
      count = Base64.encode("Now is the time for all good coders\nto learn Crystal", io)
      count.should eq 74
    end

    it "decode from stream returns number of written bytes" do
      io = IO::Memory.new
      count = Base64.decode("Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA==", io)
      count.should eq 52
    end

    it "big message" do
      a = "a" * 100000
      b = Base64.encode(a)
      Crystal::Digest::MD5.hexdigest(Base64.decode_string(b)).should eq(Crystal::Digest::MD5.hexdigest(a))
    end

    it "works for most characters" do
      a = String.build(65536 * 4) do |buf|
        65536.times { |i| buf << (i + 1).unsafe_chr }
      end
      b = Base64.encode(a)
      Crystal::Digest::MD5.hexdigest(Base64.decode_string(b)).should eq(Crystal::Digest::MD5.hexdigest(a))
    end
  end

  describe "decode cases" do
    it "decode \r\n" do
      decoded = "hahah⊙ⓧ⊙"
      {"aGFo\r\nYWjiipnik6fiipk=\r\n", "aGFo\r\nYWjiipnik6fiipk=\r\n\r\n"}.each do |encoded|
        Base64.decode(encoded).should eq(decoded.to_slice)
        Base64.decode_string(encoded).should eq(decoded)
      end
    end

    it "decode \n in multiple places" do
      decoded = "hahah⊙ⓧ⊙"
      {"aGFoYWjiipnik6fiipk=", "aGFo\nYWjiipnik6fiipk=", "aGFo\nYWji\nipnik6fiipk=",
       "aGFo\nYWji\nipni\nk6fiipk=", "aGFo\nYWji\nipni\nk6fi\nipk=",
       "aGFo\nYWji\nipni\nk6fi\nipk=\n"}.each do |encoded|
        Base64.decode(encoded).should eq(decoded.to_slice)
        Base64.decode_string(encoded).should eq(decoded)
      end
    end

    it "raise error when \n in incorrect place" do
      expect_raises Base64::Error do
        Base64.decode("aG\nFoYWjiipnik6fiipk=")
      end

      expect_raises Base64::Error do
        Base64.decode_string("aG\nFoYWjiipnik6fiipk=")
      end
    end

    it "raise error when incorrect symbol" do
      expect_raises Base64::Error do
        Base64.decode("()")
      end

      expect_raises Base64::Error do
        Base64.decode_string("()")
      end
    end

    it "raise error when incorrect size" do
      expect_raises Base64::Error do
        Base64.decode("a")
      end

      expect_raises Base64::Error do
        Base64.decode_string("a")
      end
    end

    it "decode small tail after last \n, was a bug" do
      s = "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g\nnA==\n"
      Base64.decode(s).should eq Bytes[78, 111, 119, 32, 105, 115, 32, 116, 104, 101, 32, 116, 105, 109, 101, 32, 102, 111, 114, 32, 97, 108, 108, 32, 103, 111, 111, 100, 32, 99, 111, 100, 101, 114, 115, 10, 116, 111, 32, 108, 101, 97, 114, 110, 32, 156]
    end
  end

  describe "strict" do
    it "encode" do
      assert_prints base64_strict_encode("Now is the time for all good coders\nto learn Crystal"),
        "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4gQ3J5c3RhbA=="
    end
    it "with spec symbols" do
      s = String.build { |b| (160..179).each { |i| b << i.chr } }
      se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq/CsMKxwrLCsw=="
      assert_prints base64_strict_encode(s), se
    end

    it "encode to stream returns number of written characters" do
      s = String.build { |b| (160..179).each { |i| b << i.chr } }
      io = IO::Memory.new
      Base64.strict_encode(s, io).should eq(56)
    end
  end

  describe "urlsafe" do
    it "work" do
      s = String.build { |b| (160..179).each { |i| b << i.chr } }
      se = "wqDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrcKuwq_CsMKxwrLCsw=="
      assert_prints base64_urlsafe_encode(s), se
    end

    it "encode to stream returns number of written characters" do
      s = String.build { |b| (160..179).each { |i| b << i.chr } }
      io = IO::Memory.new
      Base64.urlsafe_encode(s, io).should eq(56)
    end
  end
end