go.ketch.com/lib/goja@v0.0.1/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 BenchmarkASCIIConcat(b *testing.B) {
   153  	vm := New()
   154  
   155  	b.ResetTimer()
   156  	b.ReportAllocs()
   157  	for i := 0; i < b.N; i++ {
   158  		_, err := vm.RunString(`{let result = "ab";
   159  		for (let i = 0 ; i < 10;i++) {
   160  			result += result;
   161  		}}`)
   162  		if err != nil {
   163  			b.Fatalf("Unexpected errors %s", err)
   164  		}
   165  	}
   166  }