From d4fd2467d691a69a0ba75348086424b9fb33a297 Mon Sep 17 00:00:00 2001 From: bndw Date: Sat, 7 Feb 2026 15:20:57 -0800 Subject: wip --- envelope_test.go | 416 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100644 envelope_test.go (limited to 'envelope_test.go') diff --git a/envelope_test.go b/envelope_test.go new file mode 100644 index 0000000..8f79ad5 --- /dev/null +++ b/envelope_test.go @@ -0,0 +1,416 @@ +package nostr + +import ( + "encoding/json" + "testing" +) + +func TestEventEnvelopeMarshalJSON(t *testing.T) { + event := &Event{ + ID: "abc123", + PubKey: "def456", + CreatedAt: 1704067200, + Kind: 1, + Tags: Tags{}, + Content: "Hello", + Sig: "sig789", + } + + t.Run("client to relay", func(t *testing.T) { + env := EventEnvelope{Event: event} + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 2 { + t.Errorf("Array length = %d, want 2", len(arr)) + } + + var label string + json.Unmarshal(arr[0], &label) + if label != "EVENT" { + t.Errorf("Label = %s, want EVENT", label) + } + }) + + t.Run("relay to client", func(t *testing.T) { + env := EventEnvelope{SubscriptionID: "sub1", Event: event} + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 3 { + t.Errorf("Array length = %d, want 3", len(arr)) + } + }) +} + +func TestReqEnvelopeMarshalJSON(t *testing.T) { + env := ReqEnvelope{ + SubscriptionID: "sub1", + Filters: []Filter{ + {Kinds: []int{1}}, + {Authors: []string{"abc123"}}, + }, + } + + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []json.RawMessage + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 4 { // ["REQ", "sub1", filter1, filter2] + t.Errorf("Array length = %d, want 4", len(arr)) + } + + var label string + json.Unmarshal(arr[0], &label) + if label != "REQ" { + t.Errorf("Label = %s, want REQ", label) + } + + var subID string + json.Unmarshal(arr[1], &subID) + if subID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", subID) + } +} + +func TestCloseEnvelopeMarshalJSON(t *testing.T) { + env := CloseEnvelope{SubscriptionID: "sub1"} + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []interface{} + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 2 { + t.Errorf("Array length = %d, want 2", len(arr)) + } + if arr[0] != "CLOSE" { + t.Errorf("Label = %v, want CLOSE", arr[0]) + } + if arr[1] != "sub1" { + t.Errorf("SubscriptionID = %v, want sub1", arr[1]) + } +} + +func TestOKEnvelopeMarshalJSON(t *testing.T) { + env := OKEnvelope{ + EventID: "event123", + OK: true, + Message: "accepted", + } + + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []interface{} + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 4 { + t.Errorf("Array length = %d, want 4", len(arr)) + } + if arr[0] != "OK" { + t.Errorf("Label = %v, want OK", arr[0]) + } + if arr[1] != "event123" { + t.Errorf("EventID = %v, want event123", arr[1]) + } + if arr[2] != true { + t.Errorf("OK = %v, want true", arr[2]) + } + if arr[3] != "accepted" { + t.Errorf("Message = %v, want accepted", arr[3]) + } +} + +func TestEOSEEnvelopeMarshalJSON(t *testing.T) { + env := EOSEEnvelope{SubscriptionID: "sub1"} + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []interface{} + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 2 { + t.Errorf("Array length = %d, want 2", len(arr)) + } + if arr[0] != "EOSE" { + t.Errorf("Label = %v, want EOSE", arr[0]) + } +} + +func TestClosedEnvelopeMarshalJSON(t *testing.T) { + env := ClosedEnvelope{ + SubscriptionID: "sub1", + Message: "rate limited", + } + + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []interface{} + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 3 { + t.Errorf("Array length = %d, want 3", len(arr)) + } + if arr[0] != "CLOSED" { + t.Errorf("Label = %v, want CLOSED", arr[0]) + } +} + +func TestNoticeEnvelopeMarshalJSON(t *testing.T) { + env := NoticeEnvelope{Message: "error: rate limited"} + data, err := env.MarshalJSON() + if err != nil { + t.Fatalf("MarshalJSON() error = %v", err) + } + + var arr []interface{} + if err := json.Unmarshal(data, &arr); err != nil { + t.Fatalf("Invalid JSON: %v", err) + } + + if len(arr) != 2 { + t.Errorf("Array length = %d, want 2", len(arr)) + } + if arr[0] != "NOTICE" { + t.Errorf("Label = %v, want NOTICE", arr[0]) + } +} + +func TestParseEnvelopeEvent(t *testing.T) { + t.Run("client to relay", func(t *testing.T) { + data := `["EVENT",{"id":"abc123","pubkey":"def456","created_at":1704067200,"kind":1,"tags":[],"content":"Hello","sig":"sig789"}]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + eventEnv, ok := env.(*EventEnvelope) + if !ok { + t.Fatalf("Expected *EventEnvelope, got %T", env) + } + + if eventEnv.SubscriptionID != "" { + t.Errorf("SubscriptionID = %s, want empty", eventEnv.SubscriptionID) + } + if eventEnv.Event.ID != "abc123" { + t.Errorf("Event.ID = %s, want abc123", eventEnv.Event.ID) + } + }) + + t.Run("relay to client", func(t *testing.T) { + data := `["EVENT","sub1",{"id":"abc123","pubkey":"def456","created_at":1704067200,"kind":1,"tags":[],"content":"Hello","sig":"sig789"}]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + eventEnv, ok := env.(*EventEnvelope) + if !ok { + t.Fatalf("Expected *EventEnvelope, got %T", env) + } + + if eventEnv.SubscriptionID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", eventEnv.SubscriptionID) + } + }) +} + +func TestParseEnvelopeReq(t *testing.T) { + data := `["REQ","sub1",{"kinds":[1]},{"authors":["abc123"]}]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + reqEnv, ok := env.(*ReqEnvelope) + if !ok { + t.Fatalf("Expected *ReqEnvelope, got %T", env) + } + + if reqEnv.SubscriptionID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", reqEnv.SubscriptionID) + } + if len(reqEnv.Filters) != 2 { + t.Errorf("Filters length = %d, want 2", len(reqEnv.Filters)) + } +} + +func TestParseEnvelopeClose(t *testing.T) { + data := `["CLOSE","sub1"]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + closeEnv, ok := env.(*CloseEnvelope) + if !ok { + t.Fatalf("Expected *CloseEnvelope, got %T", env) + } + + if closeEnv.SubscriptionID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", closeEnv.SubscriptionID) + } +} + +func TestParseEnvelopeOK(t *testing.T) { + data := `["OK","event123",true,"accepted"]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + okEnv, ok := env.(*OKEnvelope) + if !ok { + t.Fatalf("Expected *OKEnvelope, got %T", env) + } + + if okEnv.EventID != "event123" { + t.Errorf("EventID = %s, want event123", okEnv.EventID) + } + if !okEnv.OK { + t.Error("OK = false, want true") + } + if okEnv.Message != "accepted" { + t.Errorf("Message = %s, want accepted", okEnv.Message) + } +} + +func TestParseEnvelopeEOSE(t *testing.T) { + data := `["EOSE","sub1"]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + eoseEnv, ok := env.(*EOSEEnvelope) + if !ok { + t.Fatalf("Expected *EOSEEnvelope, got %T", env) + } + + if eoseEnv.SubscriptionID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", eoseEnv.SubscriptionID) + } +} + +func TestParseEnvelopeClosed(t *testing.T) { + data := `["CLOSED","sub1","rate limited"]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + closedEnv, ok := env.(*ClosedEnvelope) + if !ok { + t.Fatalf("Expected *ClosedEnvelope, got %T", env) + } + + if closedEnv.SubscriptionID != "sub1" { + t.Errorf("SubscriptionID = %s, want sub1", closedEnv.SubscriptionID) + } + if closedEnv.Message != "rate limited" { + t.Errorf("Message = %s, want rate limited", closedEnv.Message) + } +} + +func TestParseEnvelopeNotice(t *testing.T) { + data := `["NOTICE","error: rate limited"]` + env, err := ParseEnvelope([]byte(data)) + if err != nil { + t.Fatalf("ParseEnvelope() error = %v", err) + } + + noticeEnv, ok := env.(*NoticeEnvelope) + if !ok { + t.Fatalf("Expected *NoticeEnvelope, got %T", env) + } + + if noticeEnv.Message != "error: rate limited" { + t.Errorf("Message = %s, want 'error: rate limited'", noticeEnv.Message) + } +} + +func TestParseEnvelopeErrors(t *testing.T) { + tests := []struct { + name string + data string + }{ + {"invalid json", "not json"}, + {"not array", `{"type":"EVENT"}`}, + {"empty array", `[]`}, + {"single element", `["EVENT"]`}, + {"unknown type", `["UNKNOWN","data"]`}, + {"invalid event length", `["EVENT","a","b","c"]`}, + {"invalid ok length", `["OK","id",true]`}, + {"invalid eose length", `["EOSE"]`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := ParseEnvelope([]byte(tt.data)) + if err == nil { + t.Error("ParseEnvelope() expected error, got nil") + } + }) + } +} + +func TestEnvelopeLabel(t *testing.T) { + tests := []struct { + env Envelope + label string + }{ + {EventEnvelope{}, "EVENT"}, + {ReqEnvelope{}, "REQ"}, + {CloseEnvelope{}, "CLOSE"}, + {OKEnvelope{}, "OK"}, + {EOSEEnvelope{}, "EOSE"}, + {ClosedEnvelope{}, "CLOSED"}, + {NoticeEnvelope{}, "NOTICE"}, + } + + for _, tt := range tests { + t.Run(tt.label, func(t *testing.T) { + if got := tt.env.Label(); got != tt.label { + t.Errorf("Label() = %s, want %s", got, tt.label) + } + }) + } +} -- cgit v1.2.3