File: ascii85_spec.rb

package info (click to toggle)
ruby-ascii85 1.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 148 kB
  • sloc: ruby: 292; makefile: 11
file content (194 lines) | stat: -rw-r--r-- 6,312 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
# encoding: utf-8

require 'minitest/autorun'

# Require implementation
require "ascii85"

describe Ascii85 do
  UNSUPPORTED_MSG = "This version of Ruby does not support encodings"

  TEST_CASES = {
    ""          => "",
    " "         => "<~+9~>",

    "\0" * 1    => "<~!!~>",
    "\0" * 2    => "<~!!!~>",
    "\0" * 3    => "<~!!!!~>",
    "\0" * 4    => "<~z~>",
    "\0" * 5    => "<~z!!~>",
    "A\0\0\0\0" => "<~5l^lb!!~>", # No z-abbreviation!

    "A"         => "<~5l~>",
    "AB"        => "<~5sb~>",
    "ABC"       => "<~5sdp~>",
    "ABCD"      => "<~5sdq,~>",
    "ABCDE"     => "<~5sdq,70~>",
    "ABCDEF"    => "<~5sdq,77I~>",
    "ABCDEFG"   => "<~5sdq,77Kc~>",
    "ABCDEFGH"  => "<~5sdq,77Kd<~>",
    "ABCDEFGHI" => "<~5sdq,77Kd<8H~>",
    "Ascii85"   => "<~6$$OMBfIs~>",

    'Antidisestablishmentarianism' => '<~6#LdYA8-*rF*(i"Ch[s(D.RU,@<-\'jDJ=0/~>',

    # Dōmo arigatō, Mr. Roboto (according to Wikipedia)
    'どうもありがとうミスターロボット' =>
        "<~j+42iJVN3:K&_E6j+<0KJW/W?W8iG`j+EuaK\"9on^Z0sZj+FJoK:LtSKB%T?~>",

    [Math::PI].pack('G') => "<~5RAV2<(&;T~>",
    [Math::E].pack('G')  => "<~5R\"n0M\\K6,~>"
  }

  it "#decode should be the inverse of #encode" do
    # Generate a random string
    test_str = String.new
    (1 + rand(255)).times do
      test_str << rand(256).chr
    end

    encoded = Ascii85.encode(test_str)
    decoded = Ascii85.decode(encoded)

    assert_equal decoded, test_str
  end

  describe "#encode" do
    it "should encode all specified test-cases correctly" do
      TEST_CASES.each_pair do |input, encoded|
        assert_equal Ascii85.encode(input), encoded
      end
    end

    it "should encode Strings in different encodings correctly" do
      unless String.new.respond_to?(:encoding)
        skip(UNSUPPORTED_MSG)
      end

      input_EUC_JP = 'どうもありがとうミスターロボット'.encode('EUC-JP')
      input_binary = input_EUC_JP.force_encoding('ASCII-8BIT')

      assert_equal Ascii85.encode(input_EUC_JP), Ascii85.encode(input_binary)
    end

    it "should produce output lines no longer than specified" do
      test_str = '0123456789' * 30

      #
      # No wrap
      #
      assert_equal Ascii85.encode(test_str, false).count("\n"), 0

      #
      # x characters per line, except for the last one
      #
      x = 2 + rand(255) # < test_str.length
      encoded = Ascii85.encode(test_str, x)

      # Determine the length of all lines
      count_arr = []
      encoded.each_line do |line|
        count_arr << line.chomp.length
      end

      # The last line is allowed to be shorter than x, so remove it
      count_arr.pop if count_arr.last <= x

      # If the end-marker is on a line of its own, the next-to-last line is
      # allowed to be shorter than specified by exactly one character
      count_arr.pop if (encoded[-3].chr =~ /[\r\n]/) and (count_arr.last == x-1)

      # Remove all line-lengths that are of length x from count_arr
      count_arr.delete_if { |len| len == x }

      # Now count_arr should be empty
      assert_empty count_arr
    end

    it "should not split the end-marker to achieve correct line length" do
      assert_equal Ascii85.encode("\0" * 4, 4), "<~z\n~>"
    end
  end

  describe "#decode" do
    it "should decode all specified test-cases correctly" do
      TEST_CASES.each_pair do |decoded, input|
        if String.new.respond_to?(:encoding)
          assert_equal Ascii85.decode(input), decoded.dup.force_encoding('ASCII-8BIT')
        else
          assert_equal Ascii85.decode(input), decoded
        end
      end
    end

    it "should accept valid input in encodings other than the default" do
      unless String.new.respond_to?(:encoding)
        skip(UNSUPPORTED_MSG)
      end

      input = "Ragnarök  τέχνη  русский язык  I ♥ Ruby"
      input_ascii85 = Ascii85.encode(input)

      # Try to encode input_ascii85 in all possible encodings and see if we
      # do the right thing in #decode.
      Encoding.list.each do |encoding|
        next if encoding.dummy?
        next unless encoding.ascii_compatible?

        # CP949 is a Microsoft Codepage for Korean, which apparently does not
        # include a backslash, even though #ascii_compatible? returns true. This
        # leads to an Ascii85::DecodingError, so we simply skip the encoding.
        next if encoding.name == "CP949"

        begin
          to_test = input_ascii85.encode(encoding)
          assert_equal Ascii85.decode(to_test).force_encoding('UTF-8'), input
        rescue Encoding::ConverterNotFoundError
          # Ignore this encoding
        end
      end
    end

    it "should only process data within delimiters" do
      assert_empty Ascii85.decode("<~~>")
      assert_empty Ascii85.decode("Doesn't contain delimiters")
      assert_empty Ascii85.decode("Mismatched ~>   delimiters 1")
      assert_empty Ascii85.decode("Mismatched <~   delimiters 2")
      assert_empty Ascii85.decode("Mismatched ~><~ delimiters 3")

      assert_equal Ascii85.decode("<~;KZGo~><~z~>"),    "Ruby"
      assert_equal Ascii85.decode("FooBar<~z~>BazQux"), "\0\0\0\0"
    end

    it "should ignore whitespace" do
      decoded = Ascii85.decode("<~6   #LdYA\r\08\n  \n\n- *rF*(i\"Ch[s \t(D.RU,@ <-\'jDJ=0\f/~>")
      assert_equal decoded, 'Antidisestablishmentarianism'
    end

    it "should return ASCII-8BIT encoded strings" do
      unless String.new.respond_to?(:encoding)
        skip(UNSUPPORTED_MSG)
      end

      assert_equal Ascii85.decode("<~;KZGo~>").encoding.name, "ASCII-8BIT"
    end

    describe "Error conditions" do
      it "should raise DecodingError if it encounters a word >= 2**32" do
        assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~s8W-#~>') }
      end

      it "should raise DecodingError if it encounters an invalid character" do
        assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!!y!!~>') }
      end

      it "should raise DecodingError if the last tuple consists of a single character" do
        assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!~>') }
      end

      it "should raise DecodingError if a z is found inside a 5-tuple" do
        assert_raises(Ascii85::DecodingError) { Ascii85.decode('<~!!z!!~>') }
      end
    end
  end
end