jruby-openssl 0.7.1 → 0.7.2

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.
@@ -1,3 +1,19 @@
1
+ == 0.7.2
2
+
3
+ - JRUBY-5126: Ignore Cipher#reset and Cipher#iv= when it's a stream
4
+ cipher (Net::SSH compatibility)
5
+ - JRUBY-5125: let Cipher#name for 'rc4' to be 'RC4' (Net::SSH
6
+ compatibility)
7
+ - JRUBY-5096: Fixed inconsistent Certificate verification behavior
8
+ - JRUBY-5060: Avoid NPE from to_pem for empty X509 Objects
9
+ - JRUBY-5059: SSLSocket ignores Timeout (Fixed)
10
+ - JRUBY-4965: implemented OpenSSL::Config
11
+ - JRUBY-5023: make Certificate#signature_algorithm return correct algo
12
+ name; "sha1WithRSAEncryption" instead of "SHA1"
13
+ - JRUBY-5024: let HMAC.new accept a String as a digest name
14
+ - JRUBY-5018: SSLSocket holds selectors, keys, preventing quick
15
+ cleanup of resources when dereferenced
16
+
1
17
  == 0.7.1
2
18
 
3
19
  - NOTE: Now BouncyCastle jars has moved out to its own gem
@@ -12,6 +12,7 @@ lib/jopenssl/version.rb
12
12
  lib/openssl/bn.rb
13
13
  lib/openssl/buffering.rb
14
14
  lib/openssl/cipher.rb
15
+ lib/openssl/config.rb
15
16
  lib/openssl/digest.rb
16
17
  lib/openssl/dummy.rb
17
18
  lib/openssl/dummyssl.rb
@@ -86,6 +87,7 @@ test/java/test_java_smime.rb
86
87
  test/openssl/ssl_server.rb
87
88
  test/openssl/test_asn1.rb
88
89
  test/openssl/test_cipher.rb
90
+ test/openssl/test_config.rb
89
91
  test/openssl/test_digest.rb
90
92
  test/openssl/test_ec.rb
91
93
  test/openssl/test_hmac.rb
data/Rakefile CHANGED
@@ -53,6 +53,7 @@ require File.dirname(__FILE__) + "/lib/jopenssl/version"
53
53
  begin
54
54
  require 'hoe'
55
55
  Hoe.plugin :gemcutter
56
+ Hoe.add_include_dirs('build_lib')
56
57
  hoe = Hoe.spec("jruby-openssl") do |p|
57
58
  p.version = Jopenssl::Version::VERSION
58
59
  p.rubyforge_name = "jruby-extras"
Binary file
@@ -1,5 +1,5 @@
1
1
  module Jopenssl
2
2
  module Version
3
- VERSION = "0.7.1"
3
+ VERSION = "0.7.2"
4
4
  end
5
5
  end
@@ -68,6 +68,7 @@ require 'jopenssl'
68
68
 
69
69
  require 'openssl/bn'
70
70
  require 'openssl/cipher'
71
+ require 'openssl/config'
71
72
  require 'openssl/digest'
72
73
  require 'openssl/pkcs7'
73
74
  require 'openssl/ssl'
@@ -0,0 +1,316 @@
1
+ =begin
2
+ = Ruby-space definitions that completes C-space funcs for Config
3
+
4
+ = Info
5
+ Copyright (C) 2010 Hiroshi Nakamura <nahi@ruby-lang.org>
6
+
7
+ = Licence
8
+ This program is licenced under the same licence as Ruby.
9
+ (See the file 'LICENCE'.)
10
+
11
+ =end
12
+
13
+ ##
14
+ # Should we care what if somebody require this file directly?
15
+ #require 'openssl'
16
+ require 'stringio'
17
+
18
+ module OpenSSL
19
+ class Config
20
+ include Enumerable
21
+
22
+ class << self
23
+ def parse(str)
24
+ c = new()
25
+ parse_config(StringIO.new(str)).each do |section, hash|
26
+ c[section] = hash
27
+ end
28
+ c
29
+ end
30
+
31
+ alias load new
32
+
33
+ def parse_config(io)
34
+ begin
35
+ parse_config_lines(io)
36
+ rescue ConfigError => e
37
+ e.message.replace("error in line #{io.lineno}: " + e.message)
38
+ raise
39
+ end
40
+ end
41
+
42
+ def get_key_string(data, section, key) # :nodoc:
43
+ if v = data[section] && data[section][key]
44
+ return v
45
+ elsif section == 'ENV'
46
+ if v = ENV[key]
47
+ return v
48
+ end
49
+ end
50
+ if v = data['default'] && data['default'][key]
51
+ return v
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def parse_config_lines(io)
58
+ section = 'default'
59
+ data = {section => {}}
60
+ while definition = get_definition(io)
61
+ definition = clear_comments(definition)
62
+ next if definition.empty?
63
+ if definition[0] == ?[
64
+ if /\[([^\]]*)\]/ =~ definition
65
+ section = $1.strip
66
+ data[section] ||= {}
67
+ else
68
+ raise ConfigError, "missing close square bracket"
69
+ end
70
+ else
71
+ if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
72
+ if $2
73
+ section = $1
74
+ key = $2
75
+ else
76
+ key = $1
77
+ end
78
+ value = unescape_value(data, section, $3)
79
+ (data[section] ||= {})[key] = value.strip
80
+ else
81
+ raise ConfigError, "missing equal sign"
82
+ end
83
+ end
84
+ end
85
+ data
86
+ end
87
+
88
+ # escape with backslash
89
+ QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
90
+ # escape with backslash and doubled dq
91
+ QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
92
+ # escaped char map
93
+ ESCAPE_MAP = {
94
+ "r" => "\r",
95
+ "n" => "\n",
96
+ "b" => "\b",
97
+ "t" => "\t",
98
+ }
99
+
100
+ def unescape_value(data, section, value)
101
+ scanned = []
102
+ while m = value.match(/['"\\$]/)
103
+ scanned << m.pre_match
104
+ c = m[0]
105
+ value = m.post_match
106
+ case c
107
+ when "'"
108
+ if m = value.match(QUOTE_REGEXP_SQ)
109
+ scanned << m[1].gsub(/\\(.)/, '\\1')
110
+ value = m.post_match
111
+ else
112
+ break
113
+ end
114
+ when '"'
115
+ if m = value.match(QUOTE_REGEXP_DQ)
116
+ scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
117
+ value = m.post_match
118
+ else
119
+ break
120
+ end
121
+ when "\\"
122
+ c = value.slice!(0, 1)
123
+ scanned << (ESCAPE_MAP[c] || c)
124
+ when "$"
125
+ ref, value = extract_reference(value)
126
+ refsec = section
127
+ if ref.index('::')
128
+ refsec, ref = ref.split('::', 2)
129
+ end
130
+ if v = get_key_string(data, refsec, ref)
131
+ scanned << v
132
+ else
133
+ raise ConfigError, "variable has no value"
134
+ end
135
+ else
136
+ raise 'must not reaced'
137
+ end
138
+ end
139
+ scanned << value
140
+ scanned.join
141
+ end
142
+
143
+ def extract_reference(value)
144
+ rest = ''
145
+ if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
146
+ value = m[1] || m[2]
147
+ rest = m.post_match
148
+ elsif [?(, ?{].include?(value[0])
149
+ raise ConfigError, "no close brace"
150
+ end
151
+ if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
152
+ return m[0], m.post_match + rest
153
+ else
154
+ raise
155
+ end
156
+ end
157
+
158
+ def clear_comments(line)
159
+ # FCOMMENT
160
+ if m = line.match(/\A([\t\n\f ]*);.*\z/)
161
+ return m[1]
162
+ end
163
+ # COMMENT
164
+ scanned = []
165
+ while m = line.match(/[#'"\\]/)
166
+ scanned << m.pre_match
167
+ c = m[0]
168
+ line = m.post_match
169
+ case c
170
+ when '#'
171
+ line = nil
172
+ break
173
+ when "'", '"'
174
+ regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
175
+ scanned << c
176
+ if m = line.match(regexp)
177
+ scanned << m[0]
178
+ line = m.post_match
179
+ else
180
+ scanned << line
181
+ line = nil
182
+ break
183
+ end
184
+ when "\\"
185
+ scanned << c
186
+ scanned << line.slice!(0, 1)
187
+ else
188
+ raise 'must not reaced'
189
+ end
190
+ end
191
+ scanned << line
192
+ scanned.join
193
+ end
194
+
195
+ def get_definition(io)
196
+ if line = get_line(io)
197
+ while /[^\\]\\\z/ =~ line
198
+ if extra = get_line(io)
199
+ line += extra
200
+ else
201
+ break
202
+ end
203
+ end
204
+ return line.strip
205
+ end
206
+ end
207
+
208
+ def get_line(io)
209
+ if line = io.gets
210
+ line.gsub(/[\r\n]*/, '')
211
+ end
212
+ end
213
+ end
214
+
215
+ def initialize(filename = nil)
216
+ @data = {}
217
+ if filename
218
+ File.open(filename.to_s) do |file|
219
+ Config.parse_config(file).each do |section, hash|
220
+ self[section] = hash
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ def get_value(section, key)
227
+ if section.nil?
228
+ raise TypeError.new('nil not allowed')
229
+ end
230
+ section = 'default' if section.empty?
231
+ get_key_string(section, key)
232
+ end
233
+
234
+ def value(arg1, arg2 = nil)
235
+ warn('Config#value is deprecated; use Config#get_value')
236
+ if arg2.nil?
237
+ section, key = 'default', arg1
238
+ else
239
+ section, key = arg1, arg2
240
+ end
241
+ section ||= 'default'
242
+ section = 'default' if section.empty?
243
+ get_key_string(section, key)
244
+ end
245
+
246
+ def add_value(section, key, value)
247
+ check_modify
248
+ (@data[section] ||= {})[key] = value
249
+ end
250
+
251
+ def [](section)
252
+ @data[section] || {}
253
+ end
254
+
255
+ def section(name)
256
+ warn('Config#section is deprecated; use Config#[]')
257
+ @data[name] || {}
258
+ end
259
+
260
+ def []=(section, pairs)
261
+ check_modify
262
+ @data[section] ||= {}
263
+ pairs.each do |key, value|
264
+ self.add_value(section, key, value)
265
+ end
266
+ end
267
+
268
+ def sections
269
+ @data.keys
270
+ end
271
+
272
+ def to_s
273
+ ary = []
274
+ @data.keys.sort.each do |section|
275
+ ary << "[ #{section} ]\n"
276
+ @data[section].keys.each do |key|
277
+ ary << "#{key}=#{@data[section][key]}\n"
278
+ end
279
+ ary << "\n"
280
+ end
281
+ ary.join
282
+ end
283
+
284
+ def each
285
+ @data.each do |section, hash|
286
+ hash.each do |key, value|
287
+ yield [section, key, value]
288
+ end
289
+ end
290
+ end
291
+
292
+ def inspect
293
+ "#<#{self.class.name} sections=#{sections.inspect}>"
294
+ end
295
+
296
+ protected
297
+
298
+ def data
299
+ @data
300
+ end
301
+
302
+ private
303
+
304
+ def initialize_copy(other)
305
+ @data = other.data.dup
306
+ end
307
+
308
+ def check_modify
309
+ raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
310
+ end
311
+
312
+ def get_key_string(section, key)
313
+ Config.get_key_string(@data, section, key)
314
+ end
315
+ end
316
+ end
@@ -101,13 +101,13 @@ class OpenSSL::TestCipher < Test::Unit::TestCase
101
101
  assert_equal(@data, decrypted_data[0...@data.size])
102
102
  end
103
103
 
104
- if PLATFORM =~ /java/
104
+ if RUBY_PLATFORM =~ /java/
105
105
  # JRuby extension - using Java padding types
106
-
106
+
107
107
  def test_disable_padding_javastyle
108
108
  test_disable_padding('NoPadding')
109
109
  end
110
-
110
+
111
111
  def test_iso10126_padding
112
112
  @c1.encrypt
113
113
  @c1.key = @key
@@ -176,7 +176,7 @@ class OpenSSL::TestCipher < Test::Unit::TestCase
176
176
  c1.key = key
177
177
  e = c1.update data
178
178
  e << c1.final
179
-
179
+
180
180
  c2 = OpenSSL::Cipher::Cipher.new("DES-CBC")
181
181
  c2.padding = 0
182
182
  c2.iv = "0" * 8
@@ -0,0 +1,290 @@
1
+ require 'openssl'
2
+ require "test/unit"
3
+ require 'tempfile'
4
+ require File.join(File.dirname(__FILE__), "utils.rb")
5
+
6
+ class OpenSSL::TestConfig < Test::Unit::TestCase
7
+ def setup
8
+ file = Tempfile.open("openssl.cnf")
9
+ file << <<__EOD__
10
+ HOME = .
11
+ [ ca ]
12
+ default_ca = CA_default
13
+ [ CA_default ]
14
+ dir = ./demoCA
15
+ certs = ./certs
16
+ __EOD__
17
+ file.close
18
+ @it = OpenSSL::Config.new(file.path)
19
+ end
20
+
21
+ def TODO_test_constants
22
+ assert(defined?(OpenSSL::Config::DEFAULT_CONFIG_FILE))
23
+ assert_nothing_raised do
24
+ OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE)
25
+ end
26
+ end
27
+
28
+ def test_s_parse
29
+ c = OpenSSL::Config.parse('')
30
+ assert_equal("[ default ]\n\n", c.to_s)
31
+ c = OpenSSL::Config.parse(@it.to_s)
32
+ assert_equal(['CA_default', 'ca', 'default'], c.sections.sort)
33
+ end
34
+
35
+ def test_s_parse_format
36
+ c = OpenSSL::Config.parse(<<__EOC__)
37
+ baz =qx\t # "baz = qx"
38
+
39
+ foo::bar = baz # shortcut section::key format
40
+ default::bar = baz # ditto
41
+ a=\t \t # "a = ": trailing spaces are ignored
42
+ =b # " = b": empty key
43
+ =c # " = c": empty key (override the above line)
44
+ d= # "c = ": trailing comment is ignored
45
+
46
+ sq = 'foo''b\\'ar'
47
+ dq ="foo""''\\""
48
+ dq2 = foo""bar
49
+ esc=a\\r\\n\\b\\tb
50
+ foo\\bar = foo\\b\\\\ar
51
+ foo\\bar::foo\\bar = baz
52
+ [default1 default2]\t\t # space is allowed in section name
53
+ fo =b ar # space allowed in value
54
+ [emptysection]
55
+ [doller ]
56
+ foo=bar
57
+ bar = $(foo)
58
+ baz = 123$(default::bar)456${foo}798
59
+ qux = ${baz}
60
+ quxx = $qux.$qux
61
+ __EOC__
62
+ assert_equal(['default', 'default1 default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort)
63
+ assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort)
64
+ assert_equal('c', c['default'][''])
65
+ assert_equal('', c['default']['a'])
66
+ assert_equal('qx', c['default']['baz'])
67
+ assert_equal('', c['default']['d'])
68
+ assert_equal('baz', c['default']['bar'])
69
+ assert_equal("foob'ar", c['default']['sq'])
70
+ assert_equal("foo''\"", c['default']['dq'])
71
+ assert_equal("foobar", c['default']['dq2'])
72
+ assert_equal("a\r\n\b\tb", c['default']['esc'])
73
+ assert_equal("foo\b\\ar", c['default']['foo\\bar'])
74
+ assert_equal('baz', c['foo']['bar'])
75
+ assert_equal('baz', c['foo\\bar']['foo\\bar'])
76
+ assert_equal('b ar', c['default1 default2']['fo'])
77
+
78
+ # dolloer
79
+ assert_equal('bar', c['doller']['foo'])
80
+ assert_equal('bar', c['doller']['bar'])
81
+ assert_equal('123baz456bar798', c['doller']['baz'])
82
+ assert_equal('123baz456bar798', c['doller']['qux'])
83
+ assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx'])
84
+
85
+ excn = assert_raise(OpenSSL::ConfigError) do
86
+ OpenSSL::Config.parse("foo = $bar")
87
+ end
88
+ assert_equal("error in line 1: variable has no value", excn.message)
89
+
90
+ excn = assert_raise(OpenSSL::ConfigError) do
91
+ OpenSSL::Config.parse("foo = $(bar")
92
+ end
93
+ assert_equal("error in line 1: no close brace", excn.message)
94
+
95
+ excn = assert_raise(OpenSSL::ConfigError) do
96
+ OpenSSL::Config.parse("f o =b ar # no space in key")
97
+ end
98
+ assert_equal("error in line 1: missing equal sign", excn.message)
99
+
100
+ excn = assert_raise(OpenSSL::ConfigError) do
101
+ OpenSSL::Config.parse(<<__EOC__)
102
+ # comment 1 # comments
103
+
104
+ #
105
+ # comment 2
106
+ \t#comment 3
107
+ [second ]\t
108
+ [third # section not terminated
109
+ __EOC__
110
+ end
111
+ assert_equal("error in line 7: missing close square bracket", excn.message)
112
+ end
113
+
114
+ def test_s_load
115
+ # alias of new
116
+ c = OpenSSL::Config.load
117
+ assert_equal("", c.to_s)
118
+ assert_equal([], c.sections)
119
+ #
120
+ file = Tempfile.open("openssl.cnf")
121
+ file.close
122
+ c = OpenSSL::Config.load(file.path)
123
+ assert_equal("[ default ]\n\n", c.to_s)
124
+ assert_equal(['default'], c.sections)
125
+ end
126
+
127
+ def test_initialize
128
+ c = OpenSSL::Config.new
129
+ assert_equal("", c.to_s)
130
+ assert_equal([], c.sections)
131
+ end
132
+
133
+ def test_initialize_with_empty_file
134
+ file = Tempfile.open("openssl.cnf")
135
+ file.close
136
+ c = OpenSSL::Config.new(file.path)
137
+ assert_equal("[ default ]\n\n", c.to_s)
138
+ assert_equal(['default'], c.sections)
139
+ end
140
+
141
+ def test_initialize_with_example_file
142
+ assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
143
+ end
144
+
145
+ def test_get_value
146
+ assert_equal('CA_default', @it.get_value('ca', 'default_ca'))
147
+ assert_equal(nil, @it.get_value('ca', 'no such key'))
148
+ assert_equal(nil, @it.get_value('no such section', 'no such key'))
149
+ assert_equal('.', @it.get_value('', 'HOME'))
150
+ assert_raise(TypeError) do
151
+ @it.get_value(nil, 'HOME') # not allowed unlike Config#value
152
+ end
153
+ # fallback to 'default' ugly...
154
+ assert_equal('.', @it.get_value('unknown', 'HOME'))
155
+ end
156
+
157
+ def test_get_value_ENV
158
+ key = ENV.keys.first
159
+ assert_not_nil(key) # make sure we have at least one ENV var.
160
+ assert_equal(ENV[key], @it.get_value('ENV', key))
161
+ end
162
+
163
+ def test_value
164
+ # supress deprecation warnings
165
+ OpenSSL::TestUtils.silent do
166
+ assert_equal('CA_default', @it.value('ca', 'default_ca'))
167
+ assert_equal(nil, @it.value('ca', 'no such key'))
168
+ assert_equal(nil, @it.value('no such section', 'no such key'))
169
+ assert_equal('.', @it.value('', 'HOME'))
170
+ assert_equal('.', @it.value(nil, 'HOME'))
171
+ assert_equal('.', @it.value('HOME'))
172
+ # fallback to 'default' ugly...
173
+ assert_equal('.', @it.value('unknown', 'HOME'))
174
+ end
175
+ end
176
+
177
+ def test_value_ENV
178
+ OpenSSL::TestUtils.silent do
179
+ key = ENV.keys.first
180
+ assert_not_nil(key) # make sure we have at least one ENV var.
181
+ assert_equal(ENV[key], @it.value('ENV', key))
182
+ end
183
+ end
184
+
185
+ def test_aref
186
+ assert_equal({'HOME' => '.'}, @it['default'])
187
+ assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default'])
188
+ assert_equal({}, @it['no_such_section'])
189
+ assert_equal({}, @it[''])
190
+ end
191
+
192
+ def test_section
193
+ OpenSSL::TestUtils.silent do
194
+ assert_equal({'HOME' => '.'}, @it.section('default'))
195
+ assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default'))
196
+ assert_equal({}, @it.section('no_such_section'))
197
+ assert_equal({}, @it.section(''))
198
+ end
199
+ end
200
+
201
+ def test_sections
202
+ assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
203
+ @it['new_section'] = {'foo' => 'bar'}
204
+ assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
205
+ @it['new_section'] = {}
206
+ assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
207
+ end
208
+
209
+ def test_add_value
210
+ c = OpenSSL::Config.new
211
+ assert_equal("", c.to_s)
212
+ # add key
213
+ c.add_value('default', 'foo', 'bar')
214
+ assert_equal("[ default ]\nfoo=bar\n\n", c.to_s)
215
+ # add another key
216
+ c.add_value('default', 'baz', 'qux')
217
+ assert_equal('bar', c['default']['foo'])
218
+ assert_equal('qux', c['default']['baz'])
219
+ # update the value
220
+ c.add_value('default', 'baz', 'quxxx')
221
+ assert_equal('bar', c['default']['foo'])
222
+ assert_equal('quxxx', c['default']['baz'])
223
+ # add section and key
224
+ c.add_value('section', 'foo', 'bar')
225
+ assert_equal('bar', c['default']['foo'])
226
+ assert_equal('quxxx', c['default']['baz'])
227
+ assert_equal('bar', c['section']['foo'])
228
+ end
229
+
230
+ def test_aset
231
+ @it['foo'] = {'bar' => 'baz'}
232
+ assert_equal({'bar' => 'baz'}, @it['foo'])
233
+ @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'}
234
+ assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
235
+
236
+ # OpenSSL::Config is add only for now.
237
+ @it['foo'] = {'foo' => 'foo'}
238
+ assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
239
+ # you cannot override or remove any section and key.
240
+ @it['foo'] = {}
241
+ assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
242
+ end
243
+
244
+ def test_each
245
+ # each returns [section, key, value] array.
246
+ ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] }
247
+ assert_equal(4, ary.size)
248
+ assert_equal('CA_default', ary[0][0])
249
+ assert_equal('CA_default', ary[1][0])
250
+ assert_equal(["ca", "default_ca", "CA_default"], ary[2])
251
+ assert_equal(["default", "HOME", "."], ary[3])
252
+ end
253
+
254
+ def test_to_s
255
+ c = OpenSSL::Config.parse("[empty]\n")
256
+ assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s)
257
+ end
258
+
259
+ def test_inspect
260
+ assert_match(/#<OpenSSL::Config sections=\[.*\]>/, @it.inspect)
261
+ end
262
+
263
+ def test_freeze
264
+ c = OpenSSL::Config.new
265
+ c['foo'] = [['key', 'value']]
266
+ c.freeze
267
+
268
+ # [ruby-core:18377]
269
+ # RuntimeError for 1.9, TypeError for 1.8
270
+ assert_raise(TypeError, /frozen/) do
271
+ c['foo'] = [['key', 'wrong']]
272
+ end
273
+ end
274
+
275
+ def test_dup
276
+ assert(!@it.sections.empty?)
277
+ c = @it.dup
278
+ assert_equal(@it.sections.sort, c.sections.sort)
279
+ @it['newsection'] = {'a' => 'b'}
280
+ assert_not_equal(@it.sections.sort, c.sections.sort)
281
+ end
282
+
283
+ def test_clone
284
+ assert(!@it.sections.empty?)
285
+ c = @it.clone
286
+ assert_equal(@it.sections.sort, c.sections.sort)
287
+ @it['newsection'] = {'a' => 'b'}
288
+ assert_not_equal(@it.sections.sort, c.sections.sort)
289
+ end
290
+ end