1# encoding: utf-8 2require_relative 'spec_helper' 3require_relative '../../shared/string/times' 4 5load_extension('string') 6 7describe :rb_str_new2, shared: true do 8 it "returns a new string object calling strlen on the passed C string" do 9 # Hardcoded to pass const char * = "hello\0invisible" 10 @s.send(@method, "hello\0not used").should == "hello" 11 end 12 13 it "encodes the string with ASCII_8BIT" do 14 @s.send(@method, "hello").encoding.should == Encoding::ASCII_8BIT 15 end 16end 17 18describe "C-API String function" do 19 before :each do 20 @s = CApiStringSpecs.new 21 end 22 23 class ValidTostrTest 24 def to_str 25 "ruby" 26 end 27 end 28 29 class InvalidTostrTest 30 def to_str 31 [] 32 end 33 end 34 35 describe "rb_str_set_len" do 36 before :each do 37 # Make a completely new copy of the string 38 # for every example (#dup doesn't cut it). 39 @str = "abcdefghij"[0..-1] 40 end 41 42 it "reduces the size of the string" do 43 @s.rb_str_set_len(@str, 5).should == "abcde" 44 end 45 46 it "inserts a NULL byte at the length" do 47 @s.rb_str_set_len(@str, 5).should == "abcde" 48 @s.rb_str_set_len(@str, 8).should == "abcde\x00gh" 49 end 50 51 it "updates the byte size and character size" do 52 @s.rb_str_set_len(@str, 4) 53 @str.bytesize.should == 4 54 @str.size.should == 4 55 @str.should == "abcd" 56 end 57 58 it "updates the string's attributes visible in C code" do 59 @s.rb_str_set_len_RSTRING_LEN(@str, 4).should == 4 60 end 61 62 it "can reveal characters written from C with RSTRING_PTR" do 63 @s.rb_str_set_len(@str, 1) 64 @str.should == "a" 65 66 @str.force_encoding(Encoding::UTF_8) 67 @s.RSTRING_PTR_set(@str, 1, 'B'.ord) 68 @s.RSTRING_PTR_set(@str, 2, 'C'.ord) 69 @s.rb_str_set_len(@str, 3) 70 71 @str.bytesize.should == 3 72 @str.should == "aBC" 73 end 74 end 75 76 describe "rb_str_buf_new" do 77 it "returns the equivalent of an empty string" do 78 buf = @s.rb_str_buf_new(10, nil) 79 buf.should == "" 80 buf.bytesize.should == 0 81 buf.size.should == 0 82 @s.RSTRING_LEN(buf).should == 0 83 end 84 85 it "returns a string with the given capacity" do 86 buf = @s.rb_str_buf_new(256, nil) 87 @s.rb_str_capacity(buf).should == 256 88 end 89 90 it "returns a string that can be appended to" do 91 str = @s.rb_str_buf_new(10, "defg") 92 str << "abcde" 93 str.should == "abcde" 94 end 95 96 it "returns a string that can be concatenated to another string" do 97 str = @s.rb_str_buf_new(10, "defg") 98 ("abcde" + str).should == "abcde" 99 end 100 101 it "returns a string whose bytes can be accessed by RSTRING_PTR" do 102 str = @s.rb_str_buf_new(10, "abcdefghi") 103 @s.rb_str_new(str, 10).should == "abcdefghi\x00" 104 end 105 106 it "returns a string that can be modified by rb_str_set_len" do 107 str = @s.rb_str_buf_new(10, "abcdef") 108 @s.rb_str_set_len(str, 4) 109 str.should == "abcd" 110 111 @s.rb_str_set_len(str, 8) 112 str[0, 6].should == "abcd\x00f" 113 @s.RSTRING_LEN(str).should == 8 114 end 115 116 it "can be used as a general buffer and reveal characters with rb_str_set_len" do 117 str = @s.rb_str_buf_new(10, "abcdef") 118 119 @s.RSTRING_PTR_set(str, 0, 195) 120 @s.RSTRING_PTR_set(str, 1, 169) 121 @s.rb_str_set_len(str, 2) 122 123 str.force_encoding(Encoding::UTF_8) 124 str.bytesize.should == 2 125 str.size.should == 1 126 str.should == "é" 127 end 128 end 129 130 describe "rb_str_buf_new2" do 131 it "returns a new string object calling strlen on the passed C string" do 132 # Hardcoded to pass const char * = "hello\0invisible" 133 @s.rb_str_buf_new2.should == "hello" 134 end 135 end 136 137 describe "rb_str_new" do 138 it "creates a new String with ASCII-8BIT Encoding" do 139 @s.rb_str_new("", 0).encoding.should == Encoding::ASCII_8BIT 140 end 141 142 it "returns a new string object from a char buffer of len characters" do 143 @s.rb_str_new("hello", 3).should == "hel" 144 end 145 146 it "returns an empty string if len is 0" do 147 @s.rb_str_new("hello", 0).should == "" 148 end 149 150 it "copy length bytes and does not stop at the first \\0 byte" do 151 @s.rb_str_new("he\x00llo", 6).should == "he\x00llo" 152 @s.rb_str_new_native("he\x00llo", 6).should == "he\x00llo" 153 end 154 155 it "returns a string from an offset char buffer" do 156 @s.rb_str_new_offset("hello", 1, 3).should == "ell" 157 end 158 end 159 160 describe "rb_str_new2" do 161 it_behaves_like :rb_str_new2, :rb_str_new2 162 end 163 164 describe "rb_str_new_cstr" do 165 it_behaves_like :rb_str_new2, :rb_str_new_cstr 166 end 167 168 describe "rb_usascii_str_new" do 169 it "creates a new String with US-ASCII Encoding from a char buffer of len characters" do 170 str = "abc".force_encoding("us-ascii") 171 result = @s.rb_usascii_str_new("abcdef", 3) 172 result.should == str 173 result.encoding.should == Encoding::US_ASCII 174 end 175 end 176 177 describe "rb_usascii_str_new_cstr" do 178 it "creates a new String with US-ASCII Encoding" do 179 str = "abc".force_encoding("us-ascii") 180 result = @s.rb_usascii_str_new_cstr("abc") 181 result.should == str 182 result.encoding.should == Encoding::US_ASCII 183 end 184 end 185 186 describe "rb_str_encode" do 187 it "returns a String in the destination encoding" do 188 result = @s.rb_str_encode("abc", Encoding::ISO_8859_1, 0, nil) 189 result.encoding.should == Encoding::ISO_8859_1 190 end 191 192 it "transcodes the String" do 193 result = @s.rb_str_encode("ありがとう", "euc-jp", 0, nil) 194 euc_jp = [0xa4, 0xa2, 0xa4, 0xea, 0xa4, 0xac, 0xa4, 0xc8, 0xa4, 0xa6].pack('C*').force_encoding("euc-jp") 195 result.should == euc_jp 196 result.encoding.should == Encoding::EUC_JP 197 end 198 199 it "returns a dup of the original String" do 200 a = "abc" 201 b = @s.rb_str_encode("abc", "us-ascii", 0, nil) 202 a.should_not equal(b) 203 end 204 205 it "returns a duplicate of the original when the encoding doesn't change" do 206 a = "abc" 207 b = @s.rb_str_encode("abc", Encoding::UTF_8, 0, nil) 208 a.should_not equal(b) 209 end 210 211 it "accepts encoding flags" do 212 xFF = [0xFF].pack('C').force_encoding('utf-8') 213 result = @s.rb_str_encode("a#{xFF}c", "us-ascii", 214 Encoding::Converter::INVALID_REPLACE, nil) 215 result.should == "a?c" 216 result.encoding.should == Encoding::US_ASCII 217 end 218 219 it "accepts an encoding options Hash specifying replacement String" do 220 # Yeah, MRI aborts with rb_bug() if the options Hash is not frozen 221 options = { replace: "b" }.freeze 222 xFF = [0xFF].pack('C').force_encoding('utf-8') 223 result = @s.rb_str_encode("a#{xFF}c", "us-ascii", 224 Encoding::Converter::INVALID_REPLACE, 225 options) 226 result.should == "abc" 227 result.encoding.should == Encoding::US_ASCII 228 end 229 end 230 231 describe "rb_str_new3" do 232 it "returns a copy of the string" do 233 str1 = "hi" 234 str2 = @s.rb_str_new3 str1 235 str1.should == str2 236 str1.should_not equal str2 237 end 238 end 239 240 describe "rb_str_new4" do 241 it "returns the original string if it is already frozen" do 242 str1 = "hi" 243 str1.freeze 244 str2 = @s.rb_str_new4 str1 245 str1.should == str2 246 str1.should equal(str2) 247 str1.frozen?.should == true 248 str2.frozen?.should == true 249 end 250 251 it "returns a frozen copy of the string" do 252 str1 = "hi" 253 str2 = @s.rb_str_new4 str1 254 str1.should == str2 255 str1.should_not equal(str2) 256 str2.frozen?.should == true 257 end 258 end 259 260 describe "rb_str_dup" do 261 it "returns a copy of the string" do 262 str1 = "hi" 263 str2 = @s.rb_str_dup str1 264 str1.should == str2 265 str1.should_not equal str2 266 end 267 end 268 269 describe "rb_str_new5" do 270 it "returns a new string with the same class as the passed string" do 271 string_class = Class.new(String) 272 template_string = string_class.new("hello world") 273 new_string = @s.rb_str_new5(template_string, "hello world", 11) 274 275 new_string.should == "hello world" 276 new_string.class.should == string_class 277 end 278 end 279 280 describe "rb_tainted_str_new" do 281 it "creates a new tainted String" do 282 newstring = @s.rb_tainted_str_new("test", 4) 283 newstring.should == "test" 284 newstring.tainted?.should be_true 285 end 286 end 287 288 describe "rb_tainted_str_new2" do 289 it "creates a new tainted String" do 290 newstring = @s.rb_tainted_str_new2("test") 291 newstring.should == "test" 292 newstring.tainted?.should be_true 293 end 294 end 295 296 describe "rb_str_append" do 297 it "appends a string to another string" do 298 @s.rb_str_append("Hello", " Goodbye").should == "Hello Goodbye" 299 end 300 301 it "raises a TypeError trying to append non-String-like object" do 302 lambda { @s.rb_str_append("Hello", 32323)}.should raise_error(TypeError) 303 end 304 305 it "changes Encoding if a string is appended to an empty string" do 306 string = "パスタ".encode(Encoding::ISO_2022_JP) 307 @s.rb_str_append("", string).encoding.should == Encoding::ISO_2022_JP 308 end 309 end 310 311 describe "rb_str_plus" do 312 it "returns a new string from concatenating two other strings" do 313 @s.rb_str_plus("Hello", " Goodbye").should == "Hello Goodbye" 314 end 315 end 316 317 describe "rb_str_times" do 318 it_behaves_like :string_times, :rb_str_times, ->(str, times) { @s.rb_str_times(str, times) } 319 end 320 321 describe "rb_str_buf_cat" do 322 it "concatenates a C string to a ruby string" do 323 @s.rb_str_buf_cat("Your house is on fire").should == "Your house is on fire?" 324 end 325 end 326 327 describe "rb_str_cat" do 328 it "concatenates a C string to ruby string" do 329 @s.rb_str_cat("Your house is on fire").should == "Your house is on fire?" 330 end 331 end 332 333 describe "rb_str_cat2" do 334 it "concatenates a C string to a ruby string" do 335 @s.rb_str_cat2("Your house is on fire").should == "Your house is on fire?" 336 end 337 end 338 339 describe "rb_str_cmp" do 340 it "returns 0 if two strings are identical" do 341 @s.rb_str_cmp("ppp", "ppp").should == 0 342 end 343 344 it "returns -1 if the first string is shorter than the second" do 345 @s.rb_str_cmp("xxx", "xxxx").should == -1 346 end 347 348 it "returns -1 if the first string is lexically less than the second" do 349 @s.rb_str_cmp("xxx", "yyy").should == -1 350 end 351 352 it "returns 1 if the first string is longer than the second" do 353 @s.rb_str_cmp("xxxx", "xxx").should == 1 354 end 355 356 it "returns 1 if the first string is lexically greater than the second" do 357 @s.rb_str_cmp("yyy", "xxx").should == 1 358 end 359 end 360 361 describe "rb_str_split" do 362 it "splits strings over a splitter" do 363 @s.rb_str_split("Hello,Goodbye").should == ["Hello", "Goodbye"] 364 end 365 end 366 367 describe "rb_str2inum" do 368 it "converts a string to a number given a base" do 369 @s.rb_str2inum("10", 10).should == 10 370 @s.rb_str2inum("A", 16).should == 10 371 end 372 end 373 374 describe "rb_cstr2inum" do 375 it "converts a C string to a Fixnum given a base" do 376 @s.rb_cstr2inum("10", 10).should == 10 377 @s.rb_cstr2inum("10", 16).should == 16 378 end 379 380 it "converts a C string to a Bignum given a base" do 381 @s.rb_cstr2inum(bignum_value.to_s, 10).should == bignum_value 382 end 383 384 it "converts a C string to a Fixnum non-strictly if base is not 0" do 385 @s.rb_cstr2inum("1234a", 10).should == 1234 386 end 387 388 it "converts a C string to a Fixnum strictly if base is 0" do 389 lambda { @s.rb_cstr2inum("1234a", 0) }.should raise_error(ArgumentError) 390 end 391 end 392 393 describe "rb_cstr_to_inum" do 394 it "converts a C string to a Fixnum given a base" do 395 @s.rb_cstr_to_inum("1234", 10, true).should == 1234 396 end 397 398 it "converts a C string to a Bignum given a base" do 399 @s.rb_cstr_to_inum(bignum_value.to_s, 10, true).should == bignum_value 400 end 401 402 it "converts a C string to a Fixnum non-strictly" do 403 @s.rb_cstr_to_inum("1234a", 10, false).should == 1234 404 end 405 406 it "converts a C string to a Fixnum strictly" do 407 lambda { @s.rb_cstr_to_inum("1234a", 10, true) }.should raise_error(ArgumentError) 408 end 409 end 410 411 describe "rb_str_subseq" do 412 it "returns a byte-indexed substring" do 413 str = "\x00\x01\x02\x03\x04".force_encoding("binary") 414 @s.rb_str_subseq(str, 1, 2).should == "\x01\x02".force_encoding("binary") 415 end 416 end 417 418 describe "rb_str_substr" do 419 it "returns a substring" do 420 "hello".length.times do |time| 421 @s.rb_str_substr("hello", 0, time + 1).should == "hello"[0..time] 422 end 423 end 424 end 425 426 describe "rb_str_to_str" do 427 it "calls #to_str to coerce the value to a String" do 428 @s.rb_str_to_str("foo").should == "foo" 429 @s.rb_str_to_str(ValidTostrTest.new).should == "ruby" 430 end 431 432 it "raises a TypeError if coercion fails" do 433 lambda { @s.rb_str_to_str(0) }.should raise_error(TypeError) 434 lambda { @s.rb_str_to_str(InvalidTostrTest.new) }.should raise_error(TypeError) 435 end 436 end 437 438 describe "RSTRING_PTR" do 439 it "returns a pointer to the string's contents" do 440 str = "abc" 441 chars = [] 442 @s.RSTRING_PTR_iterate(str) do |c| 443 chars << c 444 end 445 chars.should == [97, 98, 99] 446 end 447 448 it "allows changing the characters in the string" do 449 str = "abc" 450 @s.RSTRING_PTR_assign(str, 'A'.ord) 451 str.should == "AAA" 452 end 453 454 it "reflects changes after a rb_funcall" do 455 lamb = proc { |s| s.replace "NEW CONTENT" } 456 457 str = "beforebefore" 458 459 ret = @s.RSTRING_PTR_after_funcall(str, lamb) 460 461 str.should == "NEW CONTENT" 462 ret.should == str 463 end 464 465 it "reflects changes from native memory and from String#setbyte in bounds" do 466 str = "abc" 467 from_rstring_ptr = @s.RSTRING_PTR_after_yield(str) { str.setbyte(1, 'B'.ord) } 468 from_rstring_ptr.should == "1B2" 469 str.should == "1B2" 470 end 471 472 it "returns a pointer to the contents of encoded pointer-sized string" do 473 s = "70パク". 474 encode(Encoding::UTF_16LE). 475 force_encoding(Encoding::UTF_16LE). 476 encode(Encoding::UTF_8) 477 478 chars = [] 479 @s.RSTRING_PTR_iterate(s) do |c| 480 chars << c 481 end 482 chars.should == [55, 48, 227, 131, 145, 227, 130, 175] 483 end 484 end 485 486 describe "RSTRING_LEN" do 487 it "returns the size of the string" do 488 @s.RSTRING_LEN("gumdrops").should == 8 489 end 490 end 491 492 describe "RSTRING_LENINT" do 493 it "returns the size of a string" do 494 @s.RSTRING_LENINT("silly").should == 5 495 end 496 end 497 498 describe :string_value_macro, shared: true do 499 before :each do 500 @s = CApiStringSpecs.new 501 end 502 503 it "does not call #to_str on a String" do 504 str = "genuine" 505 str.should_not_receive(:to_str) 506 @s.send(@method, str) 507 end 508 509 it "does not call #to_s on a String" do 510 str = "genuine" 511 str.should_not_receive(:to_str) 512 @s.send(@method, str) 513 end 514 515 it "calls #to_str on non-String objects" do 516 str = mock("fake") 517 str.should_receive(:to_str).and_return("wannabe") 518 @s.send(@method, str).should == "wannabe" 519 end 520 521 it "does not call #to_s on non-String objects" do 522 str = mock("fake") 523 str.should_not_receive(:to_s) 524 lambda { @s.send(@method, str) }.should raise_error(TypeError) 525 end 526 end 527 528 describe "StringValue" do 529 it_behaves_like :string_value_macro, :StringValue 530 end 531 532 describe "SafeStringValue" do 533 it "raises for tained string when $SAFE is 1" do 534 begin 535 Thread.new { 536 $SAFE = 1 537 lambda { 538 @s.SafeStringValue("str".taint) 539 }.should raise_error(SecurityError) 540 }.join 541 ensure 542 $SAFE = 0 543 end 544 end 545 546 it_behaves_like :string_value_macro, :SafeStringValue 547 end 548 549 describe "rb_str_resize" do 550 it "reduces the size of the string" do 551 str = @s.rb_str_resize("test", 2) 552 str.size.should == 2 553 @s.RSTRING_LEN(str).should == 2 554 str.should == "te" 555 end 556 557 it "updates the string's attributes visible in C code" do 558 @s.rb_str_resize_RSTRING_LEN("test", 2).should == 2 559 end 560 561 it "increases the size of the string" do 562 expected = "test".force_encoding("US-ASCII") 563 str = @s.rb_str_resize(expected.dup, 12) 564 str.size.should == 12 565 @s.RSTRING_LEN(str).should == 12 566 str[0, 4].should == expected 567 end 568 end 569 570 describe "rb_str_inspect" do 571 it "returns the equivalent of calling #inspect on the String" do 572 @s.rb_str_inspect("value").should == %["value"] 573 end 574 end 575 576 describe "rb_str_intern" do 577 it "returns a symbol created from the string" do 578 @s.rb_str_intern("symbol").should == :symbol 579 end 580 581 it "returns a symbol even if passed an empty string" do 582 @s.rb_str_intern("").should == "".to_sym 583 end 584 585 it "returns a symbol even if the passed string contains NULL characters" do 586 @s.rb_str_intern("no\0no").should == "no\0no".to_sym 587 end 588 end 589 590 describe "rb_str_freeze" do 591 it "freezes the string" do 592 s = "" 593 @s.rb_str_freeze(s).should == s 594 s.frozen?.should be_true 595 end 596 end 597 598 describe "rb_str_hash" do 599 it "hashes the string into a number" do 600 s = "hello" 601 @s.rb_str_hash(s).should be_kind_of(Integer) 602 end 603 end 604 605 describe "rb_str_update" do 606 it "splices the replacement string into the original at the given location" do 607 @s.rb_str_update("hello", 2, 3, "wuh").should == "hewuh" 608 end 609 end 610end 611 612describe "rb_str_free" do 613 # This spec only really exists to make sure the symbol 614 # is available. There is no guarantee this even does 615 # anything at all 616 it "indicates data for a string might be freed" do 617 @s.rb_str_free("xyz").should be_nil 618 end 619end 620 621describe :rb_external_str_new, shared: true do 622 it "returns a String in the default external encoding" do 623 Encoding.default_external = "UTF-8" 624 @s.send(@method, "abc").encoding.should == Encoding::UTF_8 625 end 626 627 it "returns an ASCII-8BIT encoded string if any non-ascii bytes are present and default external is US-ASCII" do 628 Encoding.default_external = "US-ASCII" 629 x80 = [0x80].pack('C') 630 @s.send(@method, "#{x80}abc").encoding.should == Encoding::ASCII_8BIT 631 end 632 633 it "returns a tainted String" do 634 @s.send(@method, "abc").tainted?.should be_true 635 end 636end 637 638describe "C-API String function" do 639 before :each do 640 @s = CApiStringSpecs.new 641 @external = Encoding.default_external 642 @internal = Encoding.default_internal 643 end 644 645 after :each do 646 Encoding.default_external = @external 647 Encoding.default_internal = @internal 648 end 649 650 describe "rb_str_length" do 651 it "returns the string's length" do 652 @s.rb_str_length("dewdrops").should == 8 653 end 654 655 it "counts characters in multi byte encodings" do 656 @s.rb_str_length("düwdrops").should == 8 657 end 658 end 659 660 describe "rb_str_equal" do 661 it "compares two same strings" do 662 s = "hello" 663 @s.rb_str_equal(s, "hello").should be_true 664 end 665 666 it "compares two different strings" do 667 s = "hello" 668 @s.rb_str_equal(s, "hella").should be_false 669 end 670 end 671 672 describe "rb_external_str_new" do 673 it_behaves_like :rb_external_str_new, :rb_external_str_new 674 end 675 676 describe "rb_external_str_new_cstr" do 677 it_behaves_like :rb_external_str_new, :rb_external_str_new_cstr 678 end 679 680 describe "rb_external_str_new_with_enc" do 681 it "returns a String in the specified encoding" do 682 s = @s.rb_external_str_new_with_enc("abc", 3, Encoding::UTF_8) 683 s.encoding.should == Encoding::UTF_8 684 end 685 686 it "returns an ASCII-8BIT encoded String if any non-ascii bytes are present and the specified encoding is US-ASCII" do 687 x80 = [0x80].pack('C') 688 s = @s.rb_external_str_new_with_enc("#{x80}abc", 4, Encoding::US_ASCII) 689 s.encoding.should == Encoding::ASCII_8BIT 690 end 691 692 693# it "transcodes a String to Encoding.default_internal if it is set" do 694# Encoding.default_internal = Encoding::EUC_JP 695# 696# - a = "\xE3\x81\x82\xe3\x82\x8c".force_encoding("utf-8") 697# + a = [0xE3, 0x81, 0x82, 0xe3, 0x82, 0x8c].pack('C6').force_encoding("utf-8") 698# s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8) 699# - 700# - s.should == "\xA4\xA2\xA4\xEC".force_encoding("euc-jp") 701# + x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4')#.force_encoding('ascii-8bit') 702# + s.should == x 703# s.encoding.should equal(Encoding::EUC_JP) 704# end 705 706 it "transcodes a String to Encoding.default_internal if it is set" do 707 Encoding.default_internal = Encoding::EUC_JP 708 709 a = [0xE3, 0x81, 0x82, 0xe3, 0x82, 0x8c].pack('C6').force_encoding("utf-8") 710 s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8) 711 x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('euc-jp') 712 s.should == x 713 s.encoding.should equal(Encoding::EUC_JP) 714 end 715 716 it "returns a tainted String" do 717 s = @s.rb_external_str_new_with_enc("abc", 3, Encoding::US_ASCII) 718 s.tainted?.should be_true 719 end 720 end 721 722 describe "rb_locale_str_new" do 723 it "returns a String with 'locale' encoding" do 724 s = @s.rb_locale_str_new("abc", 3) 725 s.should == "abc".force_encoding(Encoding.find("locale")) 726 s.encoding.should equal(Encoding.find("locale")) 727 end 728 end 729 730 describe "rb_locale_str_new_cstr" do 731 it "returns a String with 'locale' encoding" do 732 s = @s.rb_locale_str_new_cstr("abc") 733 s.should == "abc".force_encoding(Encoding.find("locale")) 734 s.encoding.should equal(Encoding.find("locale")) 735 end 736 end 737 738 describe "rb_str_conv_enc" do 739 it "returns the original String when to encoding is not specified" do 740 a = "abc".force_encoding("us-ascii") 741 @s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should equal(a) 742 end 743 744 it "returns the original String if a transcoding error occurs" do 745 a = [0xEE].pack('C').force_encoding("utf-8") 746 @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP).should equal(a) 747 end 748 749 it "returns a transcoded String" do 750 a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8") 751 result = @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP) 752 x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8') 753 result.should == x.force_encoding("euc-jp") 754 result.encoding.should equal(Encoding::EUC_JP) 755 end 756 757 describe "when the String encoding is equal to the destination encoding" do 758 it "returns the original String" do 759 a = "abc".force_encoding("us-ascii") 760 @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should equal(a) 761 end 762 763 it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do 764 a = "abc".encode("us-ascii") 765 @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::US_ASCII).should equal(a) 766 end 767 768 it "returns the origin String if the destination encoding is ASCII-8BIT" do 769 a = "abc".force_encoding("ascii-8bit") 770 @s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::ASCII_8BIT).should equal(a) 771 end 772 end 773 end 774 775 describe "rb_str_conv_enc_opts" do 776 it "returns the original String when to encoding is not specified" do 777 a = "abc".force_encoding("us-ascii") 778 @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should equal(a) 779 end 780 781 it "returns the original String if a transcoding error occurs" do 782 a = [0xEE].pack('C').force_encoding("utf-8") 783 @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, 784 Encoding::EUC_JP, 0, nil).should equal(a) 785 end 786 787 it "returns a transcoded String" do 788 a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8") 789 result = @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, Encoding::EUC_JP, 0, nil) 790 x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8') 791 result.should == x.force_encoding("euc-jp") 792 result.encoding.should equal(Encoding::EUC_JP) 793 end 794 795 describe "when the String encoding is equal to the destination encoding" do 796 it "returns the original String" do 797 a = "abc".force_encoding("us-ascii") 798 @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, 799 Encoding::US_ASCII, 0, nil).should equal(a) 800 end 801 802 it "returns the original String if the destination encoding is ASCII compatible and the String has no high bits set" do 803 a = "abc".encode("us-ascii") 804 @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, 805 Encoding::US_ASCII, 0, nil).should equal(a) 806 end 807 808 it "returns the origin String if the destination encoding is ASCII-8BIT" do 809 a = "abc".force_encoding("ascii-8bit") 810 @s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, 811 Encoding::ASCII_8BIT, 0, nil).should equal(a) 812 end 813 end 814 end 815 816 describe "rb_str_export" do 817 it "returns the original String with the external encoding" do 818 Encoding.default_external = Encoding::ISO_8859_1 819 s = @s.rb_str_export("Hëllo") 820 s.encoding.should equal(Encoding::ISO_8859_1) 821 end 822 end 823 824 describe "rb_str_export_locale" do 825 it "returns the original String with the locale encoding" do 826 s = @s.rb_str_export_locale("abc") 827 s.should == "abc".force_encoding(Encoding.find("locale")) 828 s.encoding.should equal(Encoding.find("locale")) 829 end 830 end 831 832 describe "rb_sprintf" do 833 it "replaces the parts like sprintf" do 834 @s.rb_sprintf1("Awesome %s is replaced", "string").should == "Awesome string is replaced" 835 @s.rb_sprintf1("%s", "TestFoobarTest").should == "TestFoobarTest" 836 end 837 838 it "accepts multiple arguments" do 839 s = "Awesome %s is here with %s" 840 @s.rb_sprintf2(s, "string", "content").should == "Awesome string is here with content" 841 end 842 end 843 844 describe "rb_vsprintf" do 845 it "returns a formatted String from a variable number of arguments" do 846 s = @s.rb_vsprintf("%s, %d, %.2f", "abc", 42, 2.7); 847 s.should == "abc, 42, 2.70" 848 end 849 end 850 851 describe "rb_String" do 852 it "returns the passed argument if it is a string" do 853 @s.rb_String("a").should == "a" 854 end 855 856 it "tries to convert the passed argument to a string by calling #to_str first" do 857 @s.rb_String(ValidTostrTest.new).should == "ruby" 858 end 859 860 it "raises a TypeError if #to_str does not return a string" do 861 lambda { @s.rb_String(InvalidTostrTest.new) }.should raise_error(TypeError) 862 end 863 864 it "tries to convert the passed argument to a string by calling #to_s" do 865 @s.rb_String({"bar" => "foo"}).should == '{"bar"=>"foo"}' 866 end 867 end 868 869 describe "rb_string_value_cstr" do 870 it "returns a non-null pointer for a simple string" do 871 @s.rb_string_value_cstr("Hello").should == true 872 end 873 874 it "returns a non-null pointer for a UTF-16 string" do 875 @s.rb_string_value_cstr("Hello".encode('UTF-16BE')).should == true 876 end 877 878 it "raises an error if a string contains a null" do 879 lambda { @s.rb_string_value_cstr("Hello\0 with a null.") }.should raise_error(ArgumentError) 880 end 881 882 it "raises an error if a UTF-16 string contains a null" do 883 lambda { @s.rb_string_value_cstr("Hello\0 with a null.".encode('UTF-16BE')) }.should raise_error(ArgumentError) 884 end 885 886 end 887end 888