1# frozen_string_literal: false 2require 'test/unit' 3 4class TestEnv < Test::Unit::TestCase 5 IGNORE_CASE = /bccwin|mswin|mingw/ =~ RUBY_PLATFORM 6 PATH_ENV = "PATH" 7 INVALID_ENVVARS = [ 8 "foo\0bar", 9 "\xa1\xa1".force_encoding(Encoding::UTF_16LE), 10 "foo".force_encoding(Encoding::ISO_2022_JP), 11 ] 12 13 def assert_invalid_env(msg = nil) 14 all_assertions(msg) do |a| 15 INVALID_ENVVARS.each do |v| 16 a.for(v) do 17 assert_raise(ArgumentError) {yield v} 18 end 19 end 20 end 21 end 22 23 def setup 24 @verbose = $VERBOSE 25 $VERBOSE = nil 26 @backup = ENV.to_hash 27 ENV.delete('test') 28 ENV.delete('TEST') 29 end 30 31 def teardown 32 $VERBOSE = @verbose 33 ENV.clear 34 @backup.each {|k, v| ENV[k] = v } 35 end 36 37 def test_bracket 38 assert_nil(ENV['test']) 39 assert_nil(ENV['TEST']) 40 ENV['test'] = 'foo' 41 assert_equal('foo', ENV['test']) 42 if IGNORE_CASE 43 assert_equal('foo', ENV['TEST']) 44 else 45 assert_nil(ENV['TEST']) 46 end 47 ENV['TEST'] = 'bar' 48 assert_equal('bar', ENV['TEST']) 49 assert_predicate(ENV['TEST'], :tainted?) 50 if IGNORE_CASE 51 assert_equal('bar', ENV['test']) 52 else 53 assert_equal('foo', ENV['test']) 54 end 55 56 assert_raise(TypeError) { 57 ENV[1] 58 } 59 assert_raise(TypeError) { 60 ENV[1] = 'foo' 61 } 62 assert_raise(TypeError) { 63 ENV['test'] = 0 64 } 65 end 66 67 def test_has_value 68 val = 'a' 69 val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) 70 ENV['test'] = val[0...-1] 71 72 assert_equal(false, ENV.has_value?(val)) 73 assert_equal(false, ENV.has_value?(val.upcase)) 74 ENV['test'] = val 75 assert_equal(true, ENV.has_value?(val)) 76 assert_equal(false, ENV.has_value?(val.upcase)) 77 ENV['test'] = val.upcase 78 assert_equal(false, ENV.has_value?(val)) 79 assert_equal(true, ENV.has_value?(val.upcase)) 80 end 81 82 def test_key 83 val = 'a' 84 val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) 85 ENV['test'] = val[0...-1] 86 87 assert_nil(ENV.key(val)) 88 assert_nil(ENV.index(val)) 89 assert_nil(ENV.key(val.upcase)) 90 ENV['test'] = val 91 if IGNORE_CASE 92 assert_equal('TEST', ENV.key(val).upcase) 93 else 94 assert_equal('test', ENV.key(val)) 95 end 96 assert_nil(ENV.key(val.upcase)) 97 ENV['test'] = val.upcase 98 assert_nil(ENV.key(val)) 99 if IGNORE_CASE 100 assert_equal('TEST', ENV.key(val.upcase).upcase) 101 else 102 assert_equal('test', ENV.key(val.upcase)) 103 end 104 end 105 106 def test_delete 107 assert_invalid_env {|v| ENV.delete(v)} 108 assert_nil(ENV.delete("TEST")) 109 assert_nothing_raised { ENV.delete(PATH_ENV) } 110 end 111 112 def test_getenv 113 assert_invalid_env {|v| ENV[v]} 114 ENV[PATH_ENV] = "" 115 assert_equal("", ENV[PATH_ENV]) 116 assert_predicate(ENV[PATH_ENV], :tainted?) 117 assert_nil(ENV[""]) 118 end 119 120 def test_fetch 121 ENV["test"] = "foo" 122 assert_equal("foo", ENV.fetch("test")) 123 ENV.delete("test") 124 feature8649 = '[ruby-core:56062] [Feature #8649]' 125 e = assert_raise_with_message(KeyError, 'key not found: "test"', feature8649) do 126 ENV.fetch("test") 127 end 128 assert_same(ENV, e.receiver) 129 assert_equal("test", e.key) 130 assert_equal("foo", ENV.fetch("test", "foo")) 131 assert_equal("bar", ENV.fetch("test") { "bar" }) 132 EnvUtil.suppress_warning do 133 assert_equal("bar", ENV.fetch("test", "foo") { "bar" }) 134 end 135 assert_invalid_env {|v| ENV.fetch(v)} 136 assert_nothing_raised { ENV.fetch(PATH_ENV, "foo") } 137 ENV[PATH_ENV] = "" 138 assert_equal("", ENV.fetch(PATH_ENV)) 139 assert_predicate(ENV.fetch(PATH_ENV), :tainted?) 140 end 141 142 def test_aset 143 assert_nothing_raised { ENV["test"] = nil } 144 assert_equal(nil, ENV["test"]) 145 assert_invalid_env {|v| ENV[v] = "test"} 146 assert_invalid_env {|v| ENV["test"] = v} 147 148 begin 149 # setenv(3) allowed the name includes '=', 150 # but POSIX.1-2001 says it should fail with EINVAL. 151 # see also http://togetter.com/li/22380 152 ENV["foo=bar"] = "test" 153 assert_equal("test", ENV["foo=bar"]) 154 assert_equal("test", ENV["foo"]) 155 rescue Errno::EINVAL 156 end 157 158 ENV[PATH_ENV] = "/tmp/".taint 159 assert_equal("/tmp/", ENV[PATH_ENV]) 160 end 161 162 def test_keys 163 a = ENV.keys 164 assert_kind_of(Array, a) 165 a.each {|k| assert_kind_of(String, k) } 166 end 167 168 def test_each_key 169 ENV.each_key {|k| assert_kind_of(String, k) } 170 end 171 172 def test_values 173 a = ENV.values 174 assert_kind_of(Array, a) 175 a.each {|k| assert_kind_of(String, k) } 176 end 177 178 def test_each_value 179 ENV.each_value {|k| assert_kind_of(String, k) } 180 end 181 182 def test_each_pair 183 ENV.each_pair do |k, v| 184 assert_kind_of(String, k) 185 assert_kind_of(String, v) 186 end 187 end 188 189 def test_reject_bang 190 h1 = {} 191 ENV.each_pair {|k, v| h1[k] = v } 192 ENV["test"] = "foo" 193 ENV.reject! {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } 194 h2 = {} 195 ENV.each_pair {|k, v| h2[k] = v } 196 assert_equal(h1, h2) 197 198 assert_nil(ENV.reject! {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }) 199 end 200 201 def test_delete_if 202 h1 = {} 203 ENV.each_pair {|k, v| h1[k] = v } 204 ENV["test"] = "foo" 205 ENV.delete_if {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } 206 h2 = {} 207 ENV.each_pair {|k, v| h2[k] = v } 208 assert_equal(h1, h2) 209 210 assert_equal(ENV, ENV.delete_if {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" }) 211 end 212 213 def test_select_bang 214 h1 = {} 215 ENV.each_pair {|k, v| h1[k] = v } 216 ENV["test"] = "foo" 217 ENV.select! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } 218 h2 = {} 219 ENV.each_pair {|k, v| h2[k] = v } 220 assert_equal(h1, h2) 221 222 assert_nil(ENV.select! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }) 223 end 224 225 def test_filter_bang 226 h1 = {} 227 ENV.each_pair {|k, v| h1[k] = v } 228 ENV["test"] = "foo" 229 ENV.filter! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } 230 h2 = {} 231 ENV.each_pair {|k, v| h2[k] = v } 232 assert_equal(h1, h2) 233 234 assert_nil(ENV.filter! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }) 235 end 236 237 def test_keep_if 238 h1 = {} 239 ENV.each_pair {|k, v| h1[k] = v } 240 ENV["test"] = "foo" 241 ENV.keep_if {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } 242 h2 = {} 243 ENV.each_pair {|k, v| h2[k] = v } 244 assert_equal(h1, h2) 245 246 assert_equal(ENV, ENV.keep_if {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }) 247 end 248 249 def test_values_at 250 ENV["test"] = "foo" 251 assert_equal(["foo", "foo"], ENV.values_at("test", "test")) 252 end 253 254 def test_select 255 ENV["test"] = "foo" 256 h = ENV.select {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } 257 assert_equal(1, h.size) 258 k = h.keys.first 259 v = h.values.first 260 if IGNORE_CASE 261 assert_equal("TEST", k.upcase) 262 assert_equal("FOO", v.upcase) 263 else 264 assert_equal("test", k) 265 assert_equal("foo", v) 266 end 267 end 268 269 def test_filter 270 ENV["test"] = "foo" 271 h = ENV.filter {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } 272 assert_equal(1, h.size) 273 k = h.keys.first 274 v = h.values.first 275 if IGNORE_CASE 276 assert_equal("TEST", k.upcase) 277 assert_equal("FOO", v.upcase) 278 else 279 assert_equal("test", k) 280 assert_equal("foo", v) 281 end 282 end 283 284 def test_slice 285 ENV.clear 286 ENV["foo"] = "bar" 287 ENV["baz"] = "qux" 288 ENV["bar"] = "rab" 289 assert_equal({}, ENV.slice()) 290 assert_equal({}, ENV.slice("")) 291 assert_equal({}, ENV.slice("unknown")) 292 assert_equal({"foo"=>"bar", "baz"=>"qux"}, ENV.slice("foo", "baz")) 293 end 294 295 def test_clear 296 ENV.clear 297 assert_equal(0, ENV.size) 298 end 299 300 def test_to_s 301 assert_equal("ENV", ENV.to_s) 302 end 303 304 def test_inspect 305 ENV.clear 306 ENV["foo"] = "bar" 307 ENV["baz"] = "qux" 308 s = ENV.inspect 309 if IGNORE_CASE 310 s = s.upcase 311 assert(s == '{"FOO"=>"BAR", "BAZ"=>"QUX"}' || s == '{"BAZ"=>"QUX", "FOO"=>"BAR"}') 312 else 313 assert(s == '{"foo"=>"bar", "baz"=>"qux"}' || s == '{"baz"=>"qux", "foo"=>"bar"}') 314 end 315 end 316 317 def test_to_a 318 ENV.clear 319 ENV["foo"] = "bar" 320 ENV["baz"] = "qux" 321 a = ENV.to_a 322 assert_equal(2, a.size) 323 if IGNORE_CASE 324 a = a.map {|x| x.map {|y| y.upcase } } 325 assert(a == [%w(FOO BAR), %w(BAZ QUX)] || a == [%w(BAZ QUX), %w(FOO BAR)]) 326 else 327 assert(a == [%w(foo bar), %w(baz qux)] || a == [%w(baz qux), %w(foo bar)]) 328 end 329 end 330 331 def test_rehash 332 assert_nil(ENV.rehash) 333 end 334 335 def test_size 336 s = ENV.size 337 ENV["test"] = "foo" 338 assert_equal(s + 1, ENV.size) 339 end 340 341 def test_empty_p 342 ENV.clear 343 assert_predicate(ENV, :empty?) 344 ENV["test"] = "foo" 345 assert_not_predicate(ENV, :empty?) 346 end 347 348 def test_has_key 349 assert_not_send([ENV, :has_key?, "test"]) 350 ENV["test"] = "foo" 351 assert_send([ENV, :has_key?, "test"]) 352 assert_invalid_env {|v| ENV.has_key?(v)} 353 end 354 355 def test_assoc 356 assert_nil(ENV.assoc("test")) 357 ENV["test"] = "foo" 358 k, v = ENV.assoc("test") 359 if IGNORE_CASE 360 assert_equal("TEST", k.upcase) 361 assert_equal("FOO", v.upcase) 362 else 363 assert_equal("test", k) 364 assert_equal("foo", v) 365 end 366 assert_invalid_env {|var| ENV.assoc(var)} 367 assert_predicate(v, :tainted?) 368 assert_equal(Encoding.find("locale"), v.encoding) 369 end 370 371 def test_has_value2 372 ENV.clear 373 assert_not_send([ENV, :has_value?, "foo"]) 374 ENV["test"] = "foo" 375 assert_send([ENV, :has_value?, "foo"]) 376 end 377 378 def test_rassoc 379 ENV.clear 380 assert_nil(ENV.rassoc("foo")) 381 ENV["foo"] = "bar" 382 ENV["test"] = "foo" 383 ENV["baz"] = "qux" 384 k, v = ENV.rassoc("foo") 385 if IGNORE_CASE 386 assert_equal("TEST", k.upcase) 387 assert_equal("FOO", v.upcase) 388 else 389 assert_equal("test", k) 390 assert_equal("foo", v) 391 end 392 end 393 394 def test_to_hash 395 h = {} 396 ENV.each {|k, v| h[k] = v } 397 assert_equal(h, ENV.to_hash) 398 end 399 400 def test_to_h 401 assert_equal(ENV.to_hash, ENV.to_h) 402 assert_equal(ENV.map {|k, v| ["$#{k}", v.size]}.to_h, 403 ENV.to_h {|k, v| ["$#{k}", v.size]}) 404 end 405 406 def test_reject 407 h1 = {} 408 ENV.each_pair {|k, v| h1[k] = v } 409 ENV["test"] = "foo" 410 h2 = ENV.reject {|k, v| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } 411 assert_equal(h1, h2) 412 end 413 414 def check(as, bs) 415 if IGNORE_CASE 416 as = as.map {|xs| xs.map {|x| x.upcase } } 417 bs = bs.map {|xs| xs.map {|x| x.upcase } } 418 end 419 assert_equal(as.sort, bs.sort) 420 end 421 422 def test_shift 423 ENV.clear 424 ENV["foo"] = "bar" 425 ENV["baz"] = "qux" 426 a = ENV.shift 427 b = ENV.shift 428 check([a, b], [%w(foo bar), %w(baz qux)]) 429 assert_nil(ENV.shift) 430 end 431 432 def test_invert 433 ENV.clear 434 ENV["foo"] = "bar" 435 ENV["baz"] = "qux" 436 check(ENV.invert.to_a, [%w(bar foo), %w(qux baz)]) 437 end 438 439 def test_replace 440 ENV["foo"] = "xxx" 441 ENV.replace({"foo"=>"bar", "baz"=>"qux"}) 442 check(ENV.to_hash.to_a, [%w(foo bar), %w(baz qux)]) 443 ENV.replace({"Foo"=>"Bar", "Baz"=>"Qux"}) 444 check(ENV.to_hash.to_a, [%w(Foo Bar), %w(Baz Qux)]) 445 end 446 447 def test_update 448 ENV.clear 449 ENV["foo"] = "bar" 450 ENV["baz"] = "qux" 451 ENV.update({"baz"=>"quux","a"=>"b"}) 452 check(ENV.to_hash.to_a, [%w(foo bar), %w(baz quux), %w(a b)]) 453 454 ENV.clear 455 ENV["foo"] = "bar" 456 ENV["baz"] = "qux" 457 ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| v1 ? k + "_" + v1 + "_" + v2 : v2 } 458 check(ENV.to_hash.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)]) 459 end 460 461 def test_huge_value 462 huge_value = "bar" * 40960 463 ENV["foo"] = "bar" 464 if /mswin/ =~ RUBY_PLATFORM 465 assert_raise(Errno::EINVAL) { ENV["foo"] = huge_value } 466 assert_equal("bar", ENV["foo"]) 467 else 468 assert_nothing_raised { ENV["foo"] = huge_value } 469 assert_equal(huge_value, ENV["foo"]) 470 end 471 end 472 473 if /mswin|mingw/ =~ RUBY_PLATFORM 474 def windows_version 475 @windows_version ||= %x[ver][/Version (\d+)/, 1].to_i 476 end 477 478 def test_win32_blocksize 479 keys = [] 480 len = 32767 - ENV.to_a.flatten.inject(1) {|r,e| r + e.bytesize + 1} 481 val = "bar" * 1000 482 key = nil 483 while (len -= val.size + (key="foo#{len}").size + 2) > 0 484 keys << key 485 ENV[key] = val 486 end 487 if windows_version < 6 488 1.upto(12) {|i| 489 assert_raise(Errno::EINVAL) { ENV[key] = val } 490 } 491 else 492 1.upto(12) {|i| 493 assert_nothing_raised(Errno::EINVAL) { ENV[key] = val } 494 } 495 end 496 ensure 497 keys.each {|k| ENV.delete(k)} 498 end 499 end 500 501 def test_frozen 502 ENV[PATH_ENV] = "/" 503 ENV.each do |k, v| 504 assert_predicate(k, :frozen?) 505 assert_predicate(v, :frozen?) 506 end 507 ENV.each_key do |k| 508 assert_predicate(k, :frozen?) 509 end 510 ENV.each_value do |v| 511 assert_predicate(v, :frozen?) 512 end 513 ENV.each_key do |k| 514 assert_predicate(ENV[k], :frozen?, "[#{k.dump}]") 515 assert_predicate(ENV.fetch(k), :frozen?, "fetch(#{k.dump})") 516 end 517 end 518 519 def test_shared_substring 520 bug12475 = '[ruby-dev:49655] [Bug #12475]' 521 n = [*"0".."9"].join("")*3 522 e0 = ENV[n0 = "E#{n}"] 523 e1 = ENV[n1 = "E#{n}."] 524 ENV[n0] = nil 525 ENV[n1] = nil 526 ENV[n1.chop] = "T#{n}.".chop 527 ENV[n0], e0 = e0, ENV[n0] 528 ENV[n1], e1 = e1, ENV[n1] 529 assert_equal("T#{n}", e0, bug12475) 530 assert_nil(e1, bug12475) 531 end 532 533 if RUBY_PLATFORM =~ /bccwin|mswin|mingw/ 534 def test_memory_leak_aset 535 bug9977 = '[ruby-dev:48323] [Bug #9977]' 536 assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9977, limit: 2.0) 537 ENV.clear 538 k = 'FOO' 539 v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) 540 doit = proc {ENV[k] = v} 541 500.times(&doit) 542 end; 543 end 544 545 def test_memory_leak_select 546 bug9978 = '[ruby-dev:48325] [Bug #9978]' 547 assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9978, limit: 2.0) 548 ENV.clear 549 k = 'FOO' 550 (ENV[k] = 'bar'*5000 rescue 'bar'*1500) 551 doit = proc {ENV.select {break}} 552 500.times(&doit) 553 end; 554 end 555 556 def test_memory_crash_select 557 assert_normal_exit(<<-'end;') 558 1000.times {ENV["FOO#{i}"] = 'bar'} 559 ENV.select {ENV.clear} 560 end; 561 end 562 563 def test_memory_leak_shift 564 bug9983 = '[ruby-dev:48332] [Bug #9983]' 565 assert_no_memory_leak([], <<-'end;', "5_000.times(&doit)", bug9983, limit: 2.0) 566 ENV.clear 567 k = 'FOO' 568 v = (ENV[k] = 'bar'*5000 rescue 'bar'*1500) 569 doit = proc {ENV[k] = v; ENV.shift} 570 500.times(&doit) 571 end; 572 end 573 574 if Encoding.find("locale") == Encoding::UTF_8 575 def test_utf8 576 text = "testing \u{e5 e1 e2 e4 e3 101 3042}" 577 test = ENV["test"] 578 ENV["test"] = text 579 assert_equal text, ENV["test"] 580 ensure 581 ENV["test"] = test 582 end 583 end 584 end 585end 586