github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/string_test.go (about) 1 package goja 2 3 import ( 4 "strings" 5 "testing" 6 "unicode/utf16" 7 ) 8 9 func TestStringOOBProperties(t *testing.T) { 10 const SCRIPT = ` 11 var string = new String("str"); 12 13 string[4] = 1; 14 string[4]; 15 ` 16 17 testScript(SCRIPT, valueInt(1), t) 18 } 19 20 func TestImportedString(t *testing.T) { 21 vm := New() 22 23 testUnaryOp := func(a, expr string, result interface{}, t *testing.T) { 24 v, err := vm.RunString("a => " + expr) 25 if err != nil { 26 t.Fatal(err) 27 } 28 var fn func(a Value) (Value, error) 29 err = vm.ExportTo(v, &fn) 30 if err != nil { 31 t.Fatal(err) 32 } 33 for _, aa := range []Value{newStringValue(a), vm.ToValue(a)} { 34 res, err := fn(aa) 35 if err != nil { 36 t.Fatal(err) 37 } 38 if res.Export() != result { 39 t.Fatalf("%s, a:%v(%T). expected: %v, actual: %v", expr, aa, aa, result, res) 40 } 41 } 42 } 43 44 testBinaryOp := func(a, b, expr string, result interface{}, t *testing.T) { 45 v, err := vm.RunString("(a, b) => " + expr) 46 if err != nil { 47 t.Fatal(err) 48 } 49 var fn func(a, b Value) (Value, error) 50 err = vm.ExportTo(v, &fn) 51 if err != nil { 52 t.Fatal(err) 53 } 54 for _, aa := range []Value{newStringValue(a), vm.ToValue(a)} { 55 for _, bb := range []Value{newStringValue(b), vm.ToValue(b)} { 56 res, err := fn(aa, bb) 57 if err != nil { 58 t.Fatal(err) 59 } 60 if res.Export() != result { 61 t.Fatalf("%s, a:%v(%T), b:%v(%T). expected: %v, actual: %v", expr, aa, aa, bb, bb, result, res) 62 } 63 } 64 } 65 } 66 67 strs := []string{"shortAscii", "longlongAscii1234567890123456789", "short юникод", "long юникод 1234567890 юникод \U0001F600", "юникод", "Ascii", "long", "код"} 68 indexOfResults := [][]int{ 69 /* 70 const strs = ["shortAscii", "longlongAscii1234567890123456789", "short юникод", "long юникод 1234567890 юникод \u{1F600}", "юникод", "Ascii", "long", "код"]; 71 72 strs.forEach(a => { 73 console.log("{", strs.map(b => a.indexOf(b)).join(", "), "},"); 74 }); 75 */ 76 {0, -1, -1, -1, -1, 5, -1, -1}, 77 {-1, 0, -1, -1, -1, 8, 0, -1}, 78 {-1, -1, 0, -1, 6, -1, -1, 9}, 79 {-1, -1, -1, 0, 5, -1, 0, 8}, 80 {-1, -1, -1, -1, 0, -1, -1, 3}, 81 {-1, -1, -1, -1, -1, 0, -1, -1}, 82 {-1, -1, -1, -1, -1, -1, 0, -1}, 83 {-1, -1, -1, -1, -1, -1, -1, 0}, 84 } 85 86 lastIndexOfResults := [][]int{ 87 /* 88 strs.forEach(a => { 89 console.log("{", strs.map(b => a.lastIndexOf(b)).join(", "), "},"); 90 }); 91 */ 92 {0, -1, -1, -1, -1, 5, -1, -1}, 93 {-1, 0, -1, -1, -1, 8, 4, -1}, 94 {-1, -1, 0, -1, 6, -1, -1, 9}, 95 {-1, -1, -1, 0, 23, -1, 0, 26}, 96 {-1, -1, -1, -1, 0, -1, -1, 3}, 97 {-1, -1, -1, -1, -1, 0, -1, -1}, 98 {-1, -1, -1, -1, -1, -1, 0, -1}, 99 {-1, -1, -1, -1, -1, -1, -1, 0}, 100 } 101 102 pad := func(s, p string, n int, start bool) string { 103 if n == 0 { 104 return s 105 } 106 if p == "" { 107 p = " " 108 } 109 var b strings.Builder 110 ss := utf16.Encode([]rune(s)) 111 b.Grow(n) 112 n -= len(ss) 113 if !start { 114 b.WriteString(s) 115 } 116 if n > 0 { 117 pp := utf16.Encode([]rune(p)) 118 for n > 0 { 119 if n > len(pp) { 120 b.WriteString(p) 121 n -= len(pp) 122 } else { 123 b.WriteString(string(utf16.Decode(pp[:n]))) 124 n = 0 125 } 126 } 127 } 128 if start { 129 b.WriteString(s) 130 } 131 return b.String() 132 } 133 134 for i, a := range strs { 135 testUnaryOp(a, "JSON.parse(JSON.stringify(a))", a, t) 136 testUnaryOp(a, "a.length", int64(len(utf16.Encode([]rune(a)))), t) 137 for j, b := range strs { 138 testBinaryOp(a, b, "a === b", a == b, t) 139 testBinaryOp(a, b, "a == b", a == b, t) 140 testBinaryOp(a, b, "a + b", a+b, t) 141 testBinaryOp(a, b, "a > b", strings.Compare(a, b) > 0, t) 142 testBinaryOp(a, b, "`A${a}B${b}C`", "A"+a+"B"+b+"C", t) 143 testBinaryOp(a, b, "a.indexOf(b)", int64(indexOfResults[i][j]), t) 144 testBinaryOp(a, b, "a.lastIndexOf(b)", int64(lastIndexOfResults[i][j]), t) 145 testBinaryOp(a, b, "a.padStart(32, b)", pad(a, b, 32, true), t) 146 testBinaryOp(a, b, "a.padEnd(32, b)", pad(a, b, 32, false), t) 147 testBinaryOp(a, b, "a.replace(b, '')", strings.Replace(a, b, "", 1), t) 148 } 149 } 150 } 151 152 func TestStringFromUTF16(t *testing.T) { 153 s := StringFromUTF16([]uint16{}) 154 if s.Length() != 0 || !s.SameAs(asciiString("")) { 155 t.Fatal(s) 156 } 157 158 s = StringFromUTF16([]uint16{0xD800}) 159 if s.Length() != 1 || s.CharAt(0) != 0xD800 { 160 t.Fatal(s) 161 } 162 163 s = StringFromUTF16([]uint16{'A', 'B'}) 164 if !s.SameAs(asciiString("AB")) { 165 t.Fatal(s) 166 } 167 } 168 169 func TestStringBuilder(t *testing.T) { 170 t.Run("writeUTF8String-switch", func(t *testing.T) { 171 var sb StringBuilder 172 sb.WriteUTF8String("Head") 173 sb.WriteUTF8String("1ábc") 174 if res := sb.String().String(); res != "Head1ábc" { 175 t.Fatal(res) 176 } 177 }) 178 } 179 180 func BenchmarkASCIIConcat(b *testing.B) { 181 vm := New() 182 183 b.ResetTimer() 184 b.ReportAllocs() 185 for i := 0; i < b.N; i++ { 186 _, err := vm.RunString(`{let result = "ab"; 187 for (let i = 0 ; i < 10;i++) { 188 result += result; 189 }}`) 190 if err != nil { 191 b.Fatalf("Unexpected errors %s", err) 192 } 193 } 194 }