jsoncodec_test.go raw
1 package nostr
2
3 import (
4 "strings"
5 "testing"
6 )
7
8 func TestEmptyObjectKeyIsRejectedNotPanicked(t *testing.T) {
9 cases := []string{
10 `{"":1}`,
11 `{"id":"","":2}`,
12 `{"kinds":[1],"":null}`,
13 }
14 for _, raw := range cases {
15 if _, err := ParseEvent([]byte(raw)); err == nil {
16 t.Errorf("event %s accepted", raw)
17 }
18 if _, err := ParseFilter([]byte(raw)); err == nil {
19 t.Errorf("filter %s accepted", raw)
20 }
21 }
22 // A nested empty key in an unknown field must be skipped, not panic.
23 if _, err := ParseEvent([]byte(`{"unknown":{"":1}}`)); err == nil {
24 t.Fatal("expected missing-field error, got nil (but no panic)")
25 }
26 }
27
28 func TestEmptyKeyExtractID(t *testing.T) {
29 raw := `{"":1,"id":"eaeb41f2e1d44abc3949052406db478aeed872a64e46022daace5955cd65b316"}`
30 if got := ExtractID([]byte(raw)); got != "eaeb41f2e1d44abc3949052406db478aeed872a64e46022daace5955cd65b316" {
31 t.Fatalf("ExtractID = %q", got)
32 }
33 if got := ExtractID([]byte(`{"":1}`)); got != "" {
34 t.Fatalf("ExtractID on empty key = %q", got)
35 }
36 }
37
38 func TestSurrogateBounds(t *testing.T) {
39 if _, err := ParseJSONString([]byte(`"\uD800\u"`)); err == nil {
40 t.Fatal("truncated surrogate accepted")
41 }
42 if _, err := ParseJSONString([]byte(`"\uD800`)); err == nil {
43 t.Fatal("truncated escape accepted")
44 }
45 if _, err := ParseJSONString([]byte(`"\uDC00"`)); err == nil {
46 t.Fatal("lone low surrogate accepted")
47 }
48 got, err := ParseJSONString([]byte(`"\uD83D\uDE80"`))
49 if err != nil || got != "🚀" {
50 t.Fatalf("valid pair: %q %v", got, err)
51 }
52 }
53
54 func TestSplitArray(t *testing.T) {
55 parts, err := SplitArray([]byte(`["REQ","s",{"kinds":[1],"#e":["x"]}]`))
56 if err != nil || len(parts) != 3 {
57 t.Fatalf("parts=%q err=%v", parts, err)
58 }
59 if string(parts[0]) != `"REQ"` || string(parts[1]) != `"s"` {
60 t.Fatalf("parts: %q", parts)
61 }
62 f, err := ParseFilter(parts[2])
63 if err != nil || len(f.Kinds) != 1 || len(f.Tags["e"]) != 1 {
64 t.Fatalf("filter: %+v %v", f, err)
65 }
66 if _, err := SplitArray([]byte(`["EVENT",{"":1}]`)); err != nil {
67 t.Fatalf("split: %v", err)
68 }
69 }
70
71 func TestCodecRejectsMalformed(t *testing.T) {
72 cases := []string{
73 `{`,
74 `{"id":1}`,
75 `{"id":"zz"}`,
76 `{"kinds":[1.5]}`,
77 `{"kinds":[-1]}`,
78 `{"limit":1e3}`,
79 `{"#e":"x"}`,
80 `{"tags":[["e",1]]}`,
81 `{"content":"\q"}`,
82 }
83 for _, raw := range cases {
84 key := "event"
85 if strings.HasPrefix(raw, `{"kinds`) || strings.HasPrefix(raw, `{"#`) || strings.HasPrefix(raw, `{"limit`) {
86 key = "filter"
87 }
88 if key == "event" {
89 f := &Filter{}
90 _ = f
91 if _, err := ParseEvent([]byte(raw)); err == nil {
92 t.Errorf("event %s accepted", raw)
93 }
94 } else {
95 if _, err := ParseFilter([]byte(raw)); err == nil {
96 t.Errorf("filter %s accepted", raw)
97 }
98 }
99 }
100 }
101
102 func TestParseEventRoundTrip(t *testing.T) {
103 var sk [32]byte
104 sk[31] = 3
105 ev := &Event{Kind: 1, CreatedAt: 1700000000, Tags: Tags{{"t", "json"}}, Content: "hello \"json\"\n"}
106 if err := ev.Sign(sk); err != nil {
107 t.Fatal(err)
108 }
109 got, err := ParseEvent(ev.AppendJSON(nil))
110 if err != nil {
111 t.Fatal(err)
112 }
113 if got.ID != ev.ID || got.Content != ev.Content || len(got.Tags) != 1 {
114 t.Fatalf("round trip: %+v", got)
115 }
116 }
117