# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "String#inspect" do
  ruby_version_is ''...'2.7' do
    it "taints the result if self is tainted" do
      "foo".taint.inspect.should.tainted?
      "foo\n".taint.inspect.should.tainted?
    end

    it "untrusts the result if self is untrusted" do
      "foo".untrust.inspect.should.untrusted?
      "foo\n".untrust.inspect.should.untrusted?
    end
  end

  it "does not return a subclass instance" do
    StringSpecs::MyString.new.inspect.should be_an_instance_of(String)
  end

  it "returns a string with special characters replaced with \\<char> notation" do
    [ ["\a", '"\\a"'],
      ["\b", '"\\b"'],
      ["\t", '"\\t"'],
      ["\n", '"\\n"'],
      ["\v", '"\\v"'],
      ["\f", '"\\f"'],
      ["\r", '"\\r"'],
      ["\e", '"\\e"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with \" and \\ escaped with a backslash" do
    [ ["\"", '"\\""'],
      ["\\", '"\\\\"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with \\#<char> when # is followed by $, @, {" do
    [ ["\#$", '"\\#$"'],
      ["\#@", '"\\#@"'],
      ["\#{", '"\\#{"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with # not escaped when followed by any other character" do
    [ ["#", '"#"'],
      ["#1", '"#1"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with printable non-alphanumeric characters unescaped" do
    [ [" ", '" "'],
      ["!", '"!"'],
      ["$", '"$"'],
      ["%", '"%"'],
      ["&", '"&"'],
      ["'", '"\'"'],
      ["(", '"("'],
      [")", '")"'],
      ["*", '"*"'],
      ["+", '"+"'],
      [",", '","'],
      ["-", '"-"'],
      [".", '"."'],
      ["/", '"/"'],
      [":", '":"'],
      [";", '";"'],
      ["<", '"<"'],
      ["=", '"="'],
      [">", '">"'],
      ["?", '"?"'],
      ["@", '"@"'],
      ["[", '"["'],
      ["]", '"]"'],
      ["^", '"^"'],
      ["_", '"_"'],
      ["`", '"`"'],
      ["{", '"{"'],
      ["|", '"|"'],
      ["}", '"}"'],
      ["~", '"~"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with numeric characters unescaped" do
    [ ["0", '"0"'],
      ["1", '"1"'],
      ["2", '"2"'],
      ["3", '"3"'],
      ["4", '"4"'],
      ["5", '"5"'],
      ["6", '"6"'],
      ["7", '"7"'],
      ["8", '"8"'],
      ["9", '"9"'],
    ].should be_computed_by(:inspect)
  end

  it "returns a string with upper-case alpha characters unescaped" do
    [ ["A", '"A"'],
      ["B", '"B"'],
      ["C", '"C"'],
      ["D", '"D"'],
      ["E", '"E"'],
      ["F", '"F"'],
      ["G", '"G"'],
      ["H", '"H"'],
      ["I", '"I"'],
      ["J", '"J"'],
      ["K", '"K"'],
      ["L", '"L"'],
      ["M", '"M"'],
      ["N", '"N"'],
      ["O", '"O"'],
      ["P", '"P"'],
      ["Q", '"Q"'],
      ["R", '"R"'],
      ["S", '"S"'],
      ["T", '"T"'],
      ["U", '"U"'],
      ["V", '"V"'],
      ["W", '"W"'],
      ["X", '"X"'],
      ["Y", '"Y"'],
      ["Z", '"Z"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with lower-case alpha characters unescaped" do
    [ ["a", '"a"'],
      ["b", '"b"'],
      ["c", '"c"'],
      ["d", '"d"'],
      ["e", '"e"'],
      ["f", '"f"'],
      ["g", '"g"'],
      ["h", '"h"'],
      ["i", '"i"'],
      ["j", '"j"'],
      ["k", '"k"'],
      ["l", '"l"'],
      ["m", '"m"'],
      ["n", '"n"'],
      ["o", '"o"'],
      ["p", '"p"'],
      ["q", '"q"'],
      ["r", '"r"'],
      ["s", '"s"'],
      ["t", '"t"'],
      ["u", '"u"'],
      ["v", '"v"'],
      ["w", '"w"'],
      ["x", '"x"'],
      ["y", '"y"'],
      ["z", '"z"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with non-printing characters replaced by \\x notation" do
    # Avoid the file encoding by computing the string with #chr.
    [ [0001.chr, '"\\x01"'],
      [0002.chr, '"\\x02"'],
      [0003.chr, '"\\x03"'],
      [0004.chr, '"\\x04"'],
      [0005.chr, '"\\x05"'],
      [0006.chr, '"\\x06"'],
      [0016.chr, '"\\x0E"'],
      [0017.chr, '"\\x0F"'],
      [0020.chr, '"\\x10"'],
      [0021.chr, '"\\x11"'],
      [0022.chr, '"\\x12"'],
      [0023.chr, '"\\x13"'],
      [0024.chr, '"\\x14"'],
      [0025.chr, '"\\x15"'],
      [0026.chr, '"\\x16"'],
      [0027.chr, '"\\x17"'],
      [0030.chr, '"\\x18"'],
      [0031.chr, '"\\x19"'],
      [0032.chr, '"\\x1A"'],
      [0034.chr, '"\\x1C"'],
      [0035.chr, '"\\x1D"'],
      [0036.chr, '"\\x1E"'],
      [0037.chr, '"\\x1F"'],
      [0177.chr, '"\\x7F"'],
      [0200.chr, '"\\x80"'],
      [0201.chr, '"\\x81"'],
      [0202.chr, '"\\x82"'],
      [0203.chr, '"\\x83"'],
      [0204.chr, '"\\x84"'],
      [0205.chr, '"\\x85"'],
      [0206.chr, '"\\x86"'],
      [0207.chr, '"\\x87"'],
      [0210.chr, '"\\x88"'],
      [0211.chr, '"\\x89"'],
      [0212.chr, '"\\x8A"'],
      [0213.chr, '"\\x8B"'],
      [0214.chr, '"\\x8C"'],
      [0215.chr, '"\\x8D"'],
      [0216.chr, '"\\x8E"'],
      [0217.chr, '"\\x8F"'],
      [0220.chr, '"\\x90"'],
      [0221.chr, '"\\x91"'],
      [0222.chr, '"\\x92"'],
      [0223.chr, '"\\x93"'],
      [0224.chr, '"\\x94"'],
      [0225.chr, '"\\x95"'],
      [0226.chr, '"\\x96"'],
      [0227.chr, '"\\x97"'],
      [0230.chr, '"\\x98"'],
      [0231.chr, '"\\x99"'],
      [0232.chr, '"\\x9A"'],
      [0233.chr, '"\\x9B"'],
      [0234.chr, '"\\x9C"'],
      [0235.chr, '"\\x9D"'],
      [0236.chr, '"\\x9E"'],
      [0237.chr, '"\\x9F"'],
      [0240.chr, '"\\xA0"'],
      [0241.chr, '"\\xA1"'],
      [0242.chr, '"\\xA2"'],
      [0243.chr, '"\\xA3"'],
      [0244.chr, '"\\xA4"'],
      [0245.chr, '"\\xA5"'],
      [0246.chr, '"\\xA6"'],
      [0247.chr, '"\\xA7"'],
      [0250.chr, '"\\xA8"'],
      [0251.chr, '"\\xA9"'],
      [0252.chr, '"\\xAA"'],
      [0253.chr, '"\\xAB"'],
      [0254.chr, '"\\xAC"'],
      [0255.chr, '"\\xAD"'],
      [0256.chr, '"\\xAE"'],
      [0257.chr, '"\\xAF"'],
      [0260.chr, '"\\xB0"'],
      [0261.chr, '"\\xB1"'],
      [0262.chr, '"\\xB2"'],
      [0263.chr, '"\\xB3"'],
      [0264.chr, '"\\xB4"'],
      [0265.chr, '"\\xB5"'],
      [0266.chr, '"\\xB6"'],
      [0267.chr, '"\\xB7"'],
      [0270.chr, '"\\xB8"'],
      [0271.chr, '"\\xB9"'],
      [0272.chr, '"\\xBA"'],
      [0273.chr, '"\\xBB"'],
      [0274.chr, '"\\xBC"'],
      [0275.chr, '"\\xBD"'],
      [0276.chr, '"\\xBE"'],
      [0277.chr, '"\\xBF"'],
      [0300.chr, '"\\xC0"'],
      [0301.chr, '"\\xC1"'],
      [0302.chr, '"\\xC2"'],
      [0303.chr, '"\\xC3"'],
      [0304.chr, '"\\xC4"'],
      [0305.chr, '"\\xC5"'],
      [0306.chr, '"\\xC6"'],
      [0307.chr, '"\\xC7"'],
      [0310.chr, '"\\xC8"'],
      [0311.chr, '"\\xC9"'],
      [0312.chr, '"\\xCA"'],
      [0313.chr, '"\\xCB"'],
      [0314.chr, '"\\xCC"'],
      [0315.chr, '"\\xCD"'],
      [0316.chr, '"\\xCE"'],
      [0317.chr, '"\\xCF"'],
      [0320.chr, '"\\xD0"'],
      [0321.chr, '"\\xD1"'],
      [0322.chr, '"\\xD2"'],
      [0323.chr, '"\\xD3"'],
      [0324.chr, '"\\xD4"'],
      [0325.chr, '"\\xD5"'],
      [0326.chr, '"\\xD6"'],
      [0327.chr, '"\\xD7"'],
      [0330.chr, '"\\xD8"'],
      [0331.chr, '"\\xD9"'],
      [0332.chr, '"\\xDA"'],
      [0333.chr, '"\\xDB"'],
      [0334.chr, '"\\xDC"'],
      [0335.chr, '"\\xDD"'],
      [0336.chr, '"\\xDE"'],
      [0337.chr, '"\\xDF"'],
      [0340.chr, '"\\xE0"'],
      [0341.chr, '"\\xE1"'],
      [0342.chr, '"\\xE2"'],
      [0343.chr, '"\\xE3"'],
      [0344.chr, '"\\xE4"'],
      [0345.chr, '"\\xE5"'],
      [0346.chr, '"\\xE6"'],
      [0347.chr, '"\\xE7"'],
      [0350.chr, '"\\xE8"'],
      [0351.chr, '"\\xE9"'],
      [0352.chr, '"\\xEA"'],
      [0353.chr, '"\\xEB"'],
      [0354.chr, '"\\xEC"'],
      [0355.chr, '"\\xED"'],
      [0356.chr, '"\\xEE"'],
      [0357.chr, '"\\xEF"'],
      [0360.chr, '"\\xF0"'],
      [0361.chr, '"\\xF1"'],
      [0362.chr, '"\\xF2"'],
      [0363.chr, '"\\xF3"'],
      [0364.chr, '"\\xF4"'],
      [0365.chr, '"\\xF5"'],
      [0366.chr, '"\\xF6"'],
      [0367.chr, '"\\xF7"'],
      [0370.chr, '"\\xF8"'],
      [0371.chr, '"\\xF9"'],
      [0372.chr, '"\\xFA"'],
      [0373.chr, '"\\xFB"'],
      [0374.chr, '"\\xFC"'],
      [0375.chr, '"\\xFD"'],
      [0376.chr, '"\\xFE"'],
      [0377.chr, '"\\xFF"']
    ].should be_computed_by(:inspect)
  end

  it "returns a string with a NUL character replaced by \\x notation" do
    0.chr.inspect.should == '"\\x00"'
  end

  it "uses \\x notation for broken UTF-8 sequences" do
    "\xF0\x9F".inspect.should == '"\\xF0\\x9F"'
  end

  describe "when default external is UTF-8" do
    before :each do
      @extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8
    end

    after :each do
      Encoding.default_external = @extenc
    end

    it "returns a string with non-printing characters replaced by \\u notation for Unicode strings" do
      [ [0001.chr('utf-8'), '"\u0001"'],
        [0002.chr('utf-8'), '"\u0002"'],
        [0003.chr('utf-8'), '"\u0003"'],
        [0004.chr('utf-8'), '"\u0004"'],
        [0005.chr('utf-8'), '"\u0005"'],
        [0006.chr('utf-8'), '"\u0006"'],
        [0016.chr('utf-8'), '"\u000E"'],
        [0017.chr('utf-8'), '"\u000F"'],
        [0020.chr('utf-8'), '"\u0010"'],
        [0021.chr('utf-8'), '"\u0011"'],
        [0022.chr('utf-8'), '"\u0012"'],
        [0023.chr('utf-8'), '"\u0013"'],
        [0024.chr('utf-8'), '"\u0014"'],
        [0025.chr('utf-8'), '"\u0015"'],
        [0026.chr('utf-8'), '"\u0016"'],
        [0027.chr('utf-8'), '"\u0017"'],
        [0030.chr('utf-8'), '"\u0018"'],
        [0031.chr('utf-8'), '"\u0019"'],
        [0032.chr('utf-8'), '"\u001A"'],
        [0034.chr('utf-8'), '"\u001C"'],
        [0035.chr('utf-8'), '"\u001D"'],
        [0036.chr('utf-8'), '"\u001E"'],
        [0037.chr('utf-8'), '"\u001F"'],
        [0177.chr('utf-8'), '"\u007F"'],
        [0200.chr('utf-8'), '"\u0080"'],
        [0201.chr('utf-8'), '"\u0081"'],
        [0202.chr('utf-8'), '"\u0082"'],
        [0203.chr('utf-8'), '"\u0083"'],
        [0204.chr('utf-8'), '"\u0084"'],
        [0206.chr('utf-8'), '"\u0086"'],
        [0207.chr('utf-8'), '"\u0087"'],
        [0210.chr('utf-8'), '"\u0088"'],
        [0211.chr('utf-8'), '"\u0089"'],
        [0212.chr('utf-8'), '"\u008A"'],
        [0213.chr('utf-8'), '"\u008B"'],
        [0214.chr('utf-8'), '"\u008C"'],
        [0215.chr('utf-8'), '"\u008D"'],
        [0216.chr('utf-8'), '"\u008E"'],
        [0217.chr('utf-8'), '"\u008F"'],
        [0220.chr('utf-8'), '"\u0090"'],
        [0221.chr('utf-8'), '"\u0091"'],
        [0222.chr('utf-8'), '"\u0092"'],
        [0223.chr('utf-8'), '"\u0093"'],
        [0224.chr('utf-8'), '"\u0094"'],
        [0225.chr('utf-8'), '"\u0095"'],
        [0226.chr('utf-8'), '"\u0096"'],
        [0227.chr('utf-8'), '"\u0097"'],
        [0230.chr('utf-8'), '"\u0098"'],
        [0231.chr('utf-8'), '"\u0099"'],
        [0232.chr('utf-8'), '"\u009A"'],
        [0233.chr('utf-8'), '"\u009B"'],
        [0234.chr('utf-8'), '"\u009C"'],
        [0235.chr('utf-8'), '"\u009D"'],
        [0236.chr('utf-8'), '"\u009E"'],
        [0237.chr('utf-8'), '"\u009F"'],
      ].should be_computed_by(:inspect)
    end

    it "returns a string with a NUL character replaced by \\u notation" do
      0.chr('utf-8').inspect.should == '"\\u0000"'
    end

    it "returns a string with extended characters for Unicode strings" do
      [ [0240.chr('utf-8'), '" "'],
        [0241.chr('utf-8'), '"¡"'],
        [0242.chr('utf-8'), '"¢"'],
        [0243.chr('utf-8'), '"£"'],
        [0244.chr('utf-8'), '"¤"'],
        [0245.chr('utf-8'), '"¥"'],
        [0246.chr('utf-8'), '"¦"'],
        [0247.chr('utf-8'), '"§"'],
        [0250.chr('utf-8'), '"¨"'],
        [0251.chr('utf-8'), '"©"'],
        [0252.chr('utf-8'), '"ª"'],
        [0253.chr('utf-8'), '"«"'],
        [0254.chr('utf-8'), '"¬"'],
        [0255.chr('utf-8'), '"­"'],
        [0256.chr('utf-8'), '"®"'],
        [0257.chr('utf-8'), '"¯"'],
        [0260.chr('utf-8'), '"°"'],
        [0261.chr('utf-8'), '"±"'],
        [0262.chr('utf-8'), '"²"'],
        [0263.chr('utf-8'), '"³"'],
        [0264.chr('utf-8'), '"´"'],
        [0265.chr('utf-8'), '"µ"'],
        [0266.chr('utf-8'), '"¶"'],
        [0267.chr('utf-8'), '"·"'],
        [0270.chr('utf-8'), '"¸"'],
        [0271.chr('utf-8'), '"¹"'],
        [0272.chr('utf-8'), '"º"'],
        [0273.chr('utf-8'), '"»"'],
        [0274.chr('utf-8'), '"¼"'],
        [0275.chr('utf-8'), '"½"'],
        [0276.chr('utf-8'), '"¾"'],
        [0277.chr('utf-8'), '"¿"'],
        [0300.chr('utf-8'), '"À"'],
        [0301.chr('utf-8'), '"Á"'],
        [0302.chr('utf-8'), '"Â"'],
        [0303.chr('utf-8'), '"Ã"'],
        [0304.chr('utf-8'), '"Ä"'],
        [0305.chr('utf-8'), '"Å"'],
        [0306.chr('utf-8'), '"Æ"'],
        [0307.chr('utf-8'), '"Ç"'],
        [0310.chr('utf-8'), '"È"'],
        [0311.chr('utf-8'), '"É"'],
        [0312.chr('utf-8'), '"Ê"'],
        [0313.chr('utf-8'), '"Ë"'],
        [0314.chr('utf-8'), '"Ì"'],
        [0315.chr('utf-8'), '"Í"'],
        [0316.chr('utf-8'), '"Î"'],
        [0317.chr('utf-8'), '"Ï"'],
        [0320.chr('utf-8'), '"Ð"'],
        [0321.chr('utf-8'), '"Ñ"'],
        [0322.chr('utf-8'), '"Ò"'],
        [0323.chr('utf-8'), '"Ó"'],
        [0324.chr('utf-8'), '"Ô"'],
        [0325.chr('utf-8'), '"Õ"'],
        [0326.chr('utf-8'), '"Ö"'],
        [0327.chr('utf-8'), '"×"'],
        [0330.chr('utf-8'), '"Ø"'],
        [0331.chr('utf-8'), '"Ù"'],
        [0332.chr('utf-8'), '"Ú"'],
        [0333.chr('utf-8'), '"Û"'],
        [0334.chr('utf-8'), '"Ü"'],
        [0335.chr('utf-8'), '"Ý"'],
        [0336.chr('utf-8'), '"Þ"'],
        [0337.chr('utf-8'), '"ß"'],
        [0340.chr('utf-8'), '"à"'],
        [0341.chr('utf-8'), '"á"'],
        [0342.chr('utf-8'), '"â"'],
        [0343.chr('utf-8'), '"ã"'],
        [0344.chr('utf-8'), '"ä"'],
        [0345.chr('utf-8'), '"å"'],
        [0346.chr('utf-8'), '"æ"'],
        [0347.chr('utf-8'), '"ç"'],
        [0350.chr('utf-8'), '"è"'],
        [0351.chr('utf-8'), '"é"'],
        [0352.chr('utf-8'), '"ê"'],
        [0353.chr('utf-8'), '"ë"'],
        [0354.chr('utf-8'), '"ì"'],
        [0355.chr('utf-8'), '"í"'],
        [0356.chr('utf-8'), '"î"'],
        [0357.chr('utf-8'), '"ï"'],
        [0360.chr('utf-8'), '"ð"'],
        [0361.chr('utf-8'), '"ñ"'],
        [0362.chr('utf-8'), '"ò"'],
        [0363.chr('utf-8'), '"ó"'],
        [0364.chr('utf-8'), '"ô"'],
        [0365.chr('utf-8'), '"õ"'],
        [0366.chr('utf-8'), '"ö"'],
        [0367.chr('utf-8'), '"÷"'],
        [0370.chr('utf-8'), '"ø"'],
        [0371.chr('utf-8'), '"ù"'],
        [0372.chr('utf-8'), '"ú"'],
        [0373.chr('utf-8'), '"û"'],
        [0374.chr('utf-8'), '"ü"'],
        [0375.chr('utf-8'), '"ý"'],
        [0376.chr('utf-8'), '"þ"'],
        [0377.chr('utf-8'), '"ÿ"']
      ].should be_computed_by(:inspect)
    end
  end

  describe "when the string's encoding is different than the result's encoding" do
    describe "and the string's encoding is ASCII-compatible but the characters are non-ASCII" do
      it "returns a string with the non-ASCII characters replaced by \\x notation" do
        "\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"'
      end
    end

    describe "and the string has both ASCII-compatible and ASCII-incompatible chars" do
      it "returns a string with the non-ASCII characters replaced by \\u notation" do
        "hello привет".encode("utf-16le").inspect.should == '"hello \\u043F\\u0440\\u0438\\u0432\\u0435\\u0442"'
      end
    end
  end
end
