github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/builtin_json_test.go (about) 1 package goja 2 3 import ( 4 "encoding/json" 5 "errors" 6 "strings" 7 "testing" 8 "time" 9 ) 10 11 func TestJSONMarshalObject(t *testing.T) { 12 vm := New() 13 o := vm.NewObject() 14 o.Set("test", 42) 15 o.Set("testfunc", vm.Get("Error")) 16 b, err := json.Marshal(o) 17 if err != nil { 18 t.Fatal(err) 19 } 20 if string(b) != `{"test":42}` { 21 t.Fatalf("Unexpected value: %s", b) 22 } 23 } 24 25 func TestJSONMarshalGoDate(t *testing.T) { 26 vm := New() 27 o := vm.NewObject() 28 o.Set("test", time.Unix(86400, 0).UTC()) 29 b, err := json.Marshal(o) 30 if err != nil { 31 t.Fatal(err) 32 } 33 if string(b) != `{"test":"1970-01-02T00:00:00Z"}` { 34 t.Fatalf("Unexpected value: %s", b) 35 } 36 } 37 38 func TestJSONMarshalObjectCircular(t *testing.T) { 39 vm := New() 40 o := vm.NewObject() 41 o.Set("o", o) 42 _, err := json.Marshal(o) 43 if err == nil { 44 t.Fatal("Expected error") 45 } 46 if !strings.HasSuffix(err.Error(), "Converting circular structure to JSON") { 47 t.Fatalf("Unexpected error: %v", err) 48 } 49 } 50 51 func TestJSONStringifyCircularWrappedGo(t *testing.T) { 52 type CircularType struct { 53 Self *CircularType 54 } 55 vm := New() 56 v := CircularType{} 57 v.Self = &v 58 vm.Set("v", &v) 59 _, err := vm.RunString("JSON.stringify(v)") 60 if err == nil { 61 t.Fatal("Expected error") 62 } 63 if !strings.HasPrefix(err.Error(), "TypeError: Converting circular structure to JSON") { 64 t.Fatalf("Unexpected error: %v", err) 65 } 66 } 67 68 func TestJSONParseReviver(t *testing.T) { 69 // example from 70 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse 71 const SCRIPT = ` 72 JSON.parse('{"p": 5}', function(key, value) { 73 return typeof value === 'number' 74 ? value * 2 // return value * 2 for numbers 75 : value // return everything else unchanged 76 })["p"] 77 ` 78 79 testScript(SCRIPT, intToValue(10), t) 80 } 81 82 func TestQuoteMalformedSurrogatePair(t *testing.T) { 83 testScript(`JSON.stringify("\uD800")`, asciiString(`"\ud800"`), t) 84 } 85 86 func TestEOFWrapping(t *testing.T) { 87 vm := New() 88 89 _, err := vm.RunString("JSON.parse('{')") 90 if err == nil { 91 t.Fatal("Expected error") 92 } 93 94 if !strings.Contains(err.Error(), "Unexpected end of JSON input") { 95 t.Fatalf("Error doesn't contain human-friendly wrapper: %v", err) 96 } 97 } 98 99 type testMarshalJSONErrorStruct struct { 100 e error 101 } 102 103 func (s *testMarshalJSONErrorStruct) MarshalJSON() ([]byte, error) { 104 return nil, s.e 105 } 106 107 func TestMarshalJSONError(t *testing.T) { 108 vm := New() 109 v := testMarshalJSONErrorStruct{e: errors.New("test error")} 110 vm.Set("v", &v) 111 _, err := vm.RunString("JSON.stringify(v)") 112 if !errors.Is(err, v.e) { 113 t.Fatalf("Unexpected error: %v", err) 114 } 115 } 116 117 func BenchmarkJSONStringify(b *testing.B) { 118 b.StopTimer() 119 vm := New() 120 var createObj func(level int) *Object 121 createObj = func(level int) *Object { 122 o := vm.NewObject() 123 o.Set("field1", "test") 124 o.Set("field2", 42) 125 if level > 0 { 126 level-- 127 o.Set("obj1", createObj(level)) 128 o.Set("obj2", createObj(level)) 129 } 130 return o 131 } 132 133 o := createObj(3) 134 json := vm.Get("JSON").(*Object) 135 stringify, _ := AssertFunction(json.Get("stringify")) 136 b.StartTimer() 137 for i := 0; i < b.N; i++ { 138 stringify(nil, o) 139 } 140 }