summaryrefslogtreecommitdiff
path: root/spec/ruby/core/string/bytesplice_spec.rb
blob: 967edcba2981edf27aca33598d33a9957cf56775 (plain)
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
# -*- encoding: utf-8 -*-
# frozen_string_literal: false
require_relative '../../spec_helper'

describe "String#bytesplice" do
  ruby_version_is "3.2" do
    it "raises IndexError when index is less than -bytesize" do
      -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
    end

    it "raises IndexError when index is greater than bytesize" do
      -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
    end

    it "raises IndexError for negative length" do
      -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
    end

    it "replaces with integer indices" do
      "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
      "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
      "hello".bytesplice(0, 1, "xxx").should == "xxxello"
      "hello".bytesplice(0, 5, "xxx").should == "xxx"
      "hello".bytesplice(0, 6, "xxx").should == "xxx"
    end

    it "raises RangeError when range left boundary is less than -bytesize" do
      -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
    end

    it "replaces with ranges" do
      "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
      "hello".bytesplice(0...0, "xxx").should == "xxxhello"
      "hello".bytesplice(0..0, "xxx").should == "xxxello"
      "hello".bytesplice(0...1, "xxx").should == "xxxello"
      "hello".bytesplice(0..1, "xxx").should == "xxxllo"
      "hello".bytesplice(0..-1, "xxx").should == "xxx"
      "hello".bytesplice(0...5, "xxx").should == "xxx"
      "hello".bytesplice(0...6, "xxx").should == "xxx"
    end

    it "raises TypeError when integer index is provided without length argument" do
      -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
    end

    it "replaces on an empty string" do
      "".bytesplice(0, 0, "").should == ""
      "".bytesplice(0, 0, "xxx").should == "xxx"
    end

    it "mutates self" do
      s = "hello"
      s.bytesplice(2, 1, "xxx").should.equal?(s)
    end

    it "raises when string is frozen" do
      s = "hello".freeze
      -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
    end
  end
end

describe "String#bytesplice with multibyte characters" do
  ruby_version_is "3.2" do
    it "raises IndexError when index is out of byte size boundary" do
      -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
    end

    it "raises IndexError when index is not on a codepoint boundary" do
      -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
    end

    it "raises IndexError when length is not matching the codepoint boundary" do
      -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
      -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
    end

    it "replaces with integer indices" do
      "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
      "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
      "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
      "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
      "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
    end

    it "replaces with range" do
      "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
      "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
      "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
      "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
      "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
      "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
      "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
      "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
    end

    it "treats negative length for range as 0" do
      "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
      "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
      "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
    end

    it "raises when ranges not match codepoint boundaries" do
      -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
      -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
      # Begin is incorrect
      -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
      -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
      # End is incorrect
      -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
      -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
    end

    it "deals with a different encoded argument" do
      s = "こんにちは"
      s.encoding.should == Encoding::UTF_8
      sub = "xxxxxx"
      sub.force_encoding(Encoding::US_ASCII)

      result = s.bytesplice(0, 3, sub)
      result.should == "xxxxxxんにちは"
      result.encoding.should == Encoding::UTF_8

      s = "xxxxxx"
      s.force_encoding(Encoding::US_ASCII)
      sub = "こんにちは"
      sub.encoding.should == Encoding::UTF_8

      result = s.bytesplice(0, 3, sub)
      result.should == "こんにちはxxx"
      result.encoding.should == Encoding::UTF_8
    end
  end
end