using testify instead of testing.T methods. (#143)

This commit is contained in:
K
2024-09-09 13:50:56 +03:30
committed by GitHub
parent b2692a2584
commit c91e7b9765
21 changed files with 473 additions and 643 deletions

View File

@ -3,24 +3,19 @@ package nostr
import ( import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestCount(t *testing.T) { func TestCount(t *testing.T) {
const RELAY = "wss://relay.nostr.band" const RELAY = "wss://relay.nostr.band"
rl := mustRelayConnect(RELAY) rl := mustRelayConnect(t, RELAY)
defer rl.Close() defer rl.Close()
count, err := rl.Count(context.Background(), Filters{ count, err := rl.Count(context.Background(), Filters{
{Kinds: []int{KindContactList}, Tags: TagMap{"p": []string{"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"}}}, {Kinds: []int{KindContactList}, Tags: TagMap{"p": []string{"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"}}},
}) })
if err != nil { assert.NoError(t, err)
t.Errorf("count request failed: %v", err) assert.Greater(t, count, int64(0))
return
}
if count <= 0 {
t.Errorf("count result wrong: %v", count)
return
}
} }

View File

@ -3,6 +3,8 @@ package nostr
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestEventEnvelopeEncodingAndDecoding(t *testing.T) { func TestEventEnvelopeEncodingAndDecoding(t *testing.T) {
@ -13,67 +15,53 @@ func TestEventEnvelopeEncodingAndDecoding(t *testing.T) {
for _, raw := range eventEnvelopes { for _, raw := range eventEnvelopes {
var env EventEnvelope var env EventEnvelope
if err := json.Unmarshal([]byte(raw), &env); err != nil { err := json.Unmarshal([]byte(raw), &env)
t.Errorf("failed to parse event envelope json: %v", err) assert.NoError(t, err)
} assert.Equal(t, env.GetID(), env.ID)
if env.GetID() != env.ID { ok, _ := env.CheckSignature()
t.Errorf("error serializing event id: %s != %s", env.GetID(), env.ID) assert.True(t, ok)
}
if ok, _ := env.CheckSignature(); !ok { asJSON, err := json.Marshal(env)
t.Error("signature verification failed when it should have succeeded") assert.NoError(t, err)
} assert.Equal(t, raw, string(asJSON))
asjson, err := json.Marshal(env)
if err != nil {
t.Errorf("failed to re marshal event as json: %v", err)
}
if string(asjson) != raw {
t.Log(string(asjson))
t.Error("json serialization broken")
}
} }
} }
func TestNoticeEnvelopeEncodingAndDecoding(t *testing.T) { func TestNoticeEnvelopeEncodingAndDecoding(t *testing.T) {
src := `["NOTICE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]` noticeEnv := `["NOTICE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`
var env NoticeEnvelope var env NoticeEnvelope
json.Unmarshal([]byte(src), &env) err := json.Unmarshal([]byte(noticeEnv), &env)
if env != "kjasbdlasvdluiasvd\"kjasbdksab\\d" { assert.NoError(t, err)
t.Error("failed to decode NOTICE") assert.Equal(t, "kjasbdlasvdluiasvd\"kjasbdksab\\d", string(env))
}
if res, _ := json.Marshal(env); string(res) != src { res, err := json.Marshal(env)
t.Errorf("failed to encode NOTICE: expected '%s', got '%s'", src, string(res)) assert.NoError(t, err)
} assert.Equal(t, noticeEnv, string(res))
} }
func TestEoseEnvelopeEncodingAndDecoding(t *testing.T) { func TestEoseEnvelopeEncodingAndDecoding(t *testing.T) {
src := `["EOSE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]` eoseEnv := `["EOSE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`
var env EOSEEnvelope var env EOSEEnvelope
json.Unmarshal([]byte(src), &env) err := json.Unmarshal([]byte(eoseEnv), &env)
if env != "kjasbdlasvdluiasvd\"kjasbdksab\\d" { assert.NoError(t, err)
t.Error("failed to decode EOSE") assert.Equal(t, "kjasbdlasvdluiasvd\"kjasbdksab\\d", string(env))
}
if res, _ := json.Marshal(env); string(res) != src { res, err := json.Marshal(env)
t.Errorf("failed to encode EOSE: expected '%s', got '%s'", src, string(res)) assert.NoError(t, err)
} assert.Equal(t, eoseEnv, string(res))
} }
func TestCountEnvelopeEncodingAndDecoding(t *testing.T) { func TestCountEnvelopeEncodingAndDecoding(t *testing.T) {
src := `["COUNT","z",{"count":12}]` countEnv := `["COUNT","z",{"count":12}]`
var env CountEnvelope var env CountEnvelope
json.Unmarshal([]byte(src), &env) err := json.Unmarshal([]byte(countEnv), &env)
if *env.Count != 12 { assert.NoError(t, err)
t.Error("failed to decode COUNT") assert.Equal(t, int64(12), *env.Count)
}
if res, _ := json.Marshal(env); string(res) != src { res, err := json.Marshal(env)
t.Errorf("failed to encode COUNT: expected '%s', got '%s'", src, string(res)) assert.NoError(t, err)
} assert.Equal(t, countEnv, string(res))
} }
func TestOKEnvelopeEncodingAndDecoding(t *testing.T) { func TestOKEnvelopeEncodingAndDecoding(t *testing.T) {
@ -84,35 +72,35 @@ func TestOKEnvelopeEncodingAndDecoding(t *testing.T) {
for _, raw := range okEnvelopes { for _, raw := range okEnvelopes {
var env OKEnvelope var env OKEnvelope
if err := json.Unmarshal([]byte(raw), &env); err != nil { err := json.Unmarshal([]byte(raw), &env)
t.Errorf("failed to parse ok envelope json: %v", err) assert.NoError(t, err)
}
asjson, err := json.Marshal(env) asJSON, err := json.Marshal(env)
if err != nil { assert.NoError(t, err)
t.Errorf("failed to re marshal ok as json: %v", err) assert.Equal(t, raw, string(asJSON))
}
if string(asjson) != raw {
t.Log(string(asjson))
t.Error("json serialization broken")
}
} }
} }
func TestClosedEnvelopeEncodingAndDecoding(t *testing.T) { func TestClosedEnvelopeEncodingAndDecoding(t *testing.T) {
for _, src := range []string{ closeEnvelopes := []string{
`["CLOSED","_","error: something went wrong"]`, `["CLOSED","_","error: something went wrong"]`,
`["CLOSED",":1","auth-required: take a selfie and send it to the CIA"]`, `["CLOSED",":1","auth-required: take a selfie and send it to the CIA"]`,
} { }
for _, raw := range closeEnvelopes {
var env ClosedEnvelope var env ClosedEnvelope
json.Unmarshal([]byte(src), &env) err := json.Unmarshal([]byte(raw), &env)
if env.SubscriptionID != "_" && env.SubscriptionID != ":1" { assert.NoError(t, err)
t.Error("failed to decode CLOSED") assert.Condition(t, func() (success bool) {
} if env.SubscriptionID != "_" && env.SubscriptionID != ":1" {
if res, _ := json.Marshal(env); string(res) != src { return false
t.Errorf("failed to encode CLOSED: expected '%s', got '%s'", src, string(res)) }
} return true
})
res, err := json.Marshal(env)
assert.NoError(t, err)
assert.Equal(t, raw, string(res))
} }
} }
@ -124,19 +112,12 @@ func TestAuthEnvelopeEncodingAndDecoding(t *testing.T) {
for _, raw := range authEnvelopes { for _, raw := range authEnvelopes {
var env AuthEnvelope var env AuthEnvelope
if err := json.Unmarshal([]byte(raw), &env); err != nil { err := json.Unmarshal([]byte(raw), &env)
t.Errorf("failed to parse auth envelope json: %v", err) assert.NoError(t, err)
}
asjson, err := json.Marshal(env) asJSON, err := json.Marshal(env)
if err != nil { assert.NoError(t, err)
t.Errorf("failed to re marshal auth as json: %v", err) assert.Equal(t, raw, string(asJSON))
}
if string(asjson) != raw {
t.Log(string(asjson))
t.Error("json serialization broken")
}
} }
} }
@ -184,12 +165,12 @@ func TestParseMessage(t *testing.T) {
if testCase.ExpectedEnvelope == nil && envelope == nil { if testCase.ExpectedEnvelope == nil && envelope == nil {
return return
} }
if testCase.ExpectedEnvelope == nil && envelope != nil {
t.Fatalf("expected nil but got %v\n", envelope) if testCase.ExpectedEnvelope == nil {
} assert.NotNil(t, envelope, "expected nil but got %v\n", envelope)
if testCase.ExpectedEnvelope.String() != envelope.String() {
t.Fatalf("unexpected output:\n %s\n != %s", testCase.ExpectedEnvelope, envelope)
} }
assert.Equal(t, testCase.ExpectedEnvelope.String(), envelope.String())
}) })
} }
} }

View File

@ -4,19 +4,18 @@ import (
"context" "context"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
) )
func TestEOSEMadness(t *testing.T) { func TestEOSEMadness(t *testing.T) {
rl := mustRelayConnect(RELAY) rl := mustRelayConnect(t, RELAY)
defer rl.Close() defer rl.Close()
sub, err := rl.Subscribe(context.Background(), Filters{ sub, err := rl.Subscribe(context.Background(), Filters{
{Kinds: []int{KindTextNote}, Limit: 2}, {Kinds: []int{KindTextNote}, Limit: 2},
}) })
if err != nil { assert.NoError(t, err)
t.Errorf("subscription failed: %v", err)
return
}
timeout := time.After(3 * time.Second) timeout := time.After(3 * time.Second)
n := 0 n := 0
@ -25,15 +24,13 @@ func TestEOSEMadness(t *testing.T) {
for { for {
select { select {
case event := <-sub.Events: case event := <-sub.Events:
if event == nil { assert.NotNil(t, event)
t.Fatalf("event is nil: %v", event)
}
n++ n++
case <-sub.EndOfStoredEvents: case <-sub.EndOfStoredEvents:
e++ e++
if e > 1 { assert.Condition(t, func() (success bool) {
t.Fatalf("eose infinite loop") return !(e > 1)
} }, "eose infinite loop")
continue continue
case <-rl.Context().Done(): case <-rl.Context().Done():
t.Fatalf("connection closed: %v", rl.Context().Err()) t.Fatalf("connection closed: %v", rl.Context().Err())
@ -43,10 +40,8 @@ func TestEOSEMadness(t *testing.T) {
} }
end: end:
if e != 1 { assert.Equal(t, 1, e)
t.Fatalf("didn't get an eose") assert.Condition(t, func() (success bool) {
} return n >= 2
if n < 2 { })
t.Fatalf("didn't get events")
}
} }

View File

@ -3,6 +3,8 @@ package nostr
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestEventParsingAndVerifying(t *testing.T) { func TestEventParsingAndVerifying(t *testing.T) {
@ -15,27 +17,17 @@ func TestEventParsingAndVerifying(t *testing.T) {
for _, raw := range rawEvents { for _, raw := range rawEvents {
var ev Event var ev Event
if err := json.Unmarshal([]byte(raw), &ev); err != nil { err := json.Unmarshal([]byte(raw), &ev)
t.Errorf("failed to parse event json: %v", err) assert.NoError(t, err)
}
if ev.GetID() != ev.ID { assert.Equal(t, ev.ID, ev.GetID())
t.Errorf("error serializing event id: %s != %s", ev.GetID(), ev.ID)
}
if ok, _ := ev.CheckSignature(); !ok { ok, _ := ev.CheckSignature()
t.Error("signature verification failed when it should have succeeded") assert.True(t, ok, "signature verification failed when it should have succeeded")
}
asjson, err := json.Marshal(ev) asJSON, err := json.Marshal(ev)
if err != nil { assert.NoError(t, err)
t.Errorf("failed to re marshal event as json: %v", err) assert.Equal(t, raw, string(asJSON))
}
if string(asjson) != raw {
t.Log(string(asjson))
t.Error("json serialization broken")
}
} }
} }
@ -54,33 +46,26 @@ func TestEventSerialization(t *testing.T) {
for _, evt := range events { for _, evt := range events {
b, err := json.Marshal(evt) b, err := json.Marshal(evt)
if err != nil { assert.NoError(t, err)
t.Log(evt)
t.Error("failed to serialize this event")
}
var re Event var re Event
if err := json.Unmarshal(b, &re); err != nil { err = json.Unmarshal(b, &re)
t.Log(string(b)) assert.NoError(t, err)
t.Error("failed to re parse event just serialized")
}
if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content || assert.Condition(t, func() (success bool) {
evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig || if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content ||
len(evt.Tags) != len(re.Tags) { evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig ||
t.Error("reparsed event differs from original") len(evt.Tags) != len(re.Tags) {
} return false
}
return true
}, "re-parsed event differs from original")
for i := range evt.Tags { for i := range evt.Tags {
if len(evt.Tags[i]) != len(re.Tags[i]) { assert.Equal(t, len(evt.Tags[i]), len(re.Tags[i]), "re-parsed tags %d length differ from original", i)
t.Errorf("reparsed tags %d length differ from original", i)
continue
}
for j := range evt.Tags[i] { for j := range evt.Tags[i] {
if evt.Tags[i][j] != re.Tags[i][j] { assert.Equal(t, re.Tags[i][j], evt.Tags[i][j], "re-parsed tag content %d %d length differ from original", i, j)
t.Errorf("reparsed tag content %d %d length differ from original", i, j)
}
} }
} }
} }
@ -101,39 +86,44 @@ func TestEventSerializationWithExtraFields(t *testing.T) {
evt.SetExtra("malf", "hello") evt.SetExtra("malf", "hello")
b, err := json.Marshal(evt) b, err := json.Marshal(evt)
if err != nil { assert.NoError(t, err)
t.Log(evt)
t.Error("failed to serialize this event")
}
var re Event var re Event
if err := json.Unmarshal(b, &re); err != nil { err = json.Unmarshal(b, &re)
t.Log(string(b)) assert.NoError(t, err)
t.Error("failed to re parse event just serialized")
}
if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content || assert.Condition(t, func() (success bool) {
evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig || if evt.ID != re.ID || evt.PubKey != re.PubKey || evt.Content != re.Content ||
len(evt.Tags) != len(re.Tags) { evt.CreatedAt != re.CreatedAt || evt.Sig != re.Sig ||
t.Error("reparsed event differs from original") len(evt.Tags) != len(re.Tags) {
} return false
}
return true
}, "reparsed event differs from original")
if evt.GetExtra("malf").(string) != evt.GetExtraString("malf") || evt.GetExtraString("malf") != "hello" { assert.Condition(t, func() (success bool) {
t.Errorf("failed to parse extra string") if evt.GetExtra("malf").(string) != evt.GetExtraString("malf") || evt.GetExtraString("malf") != "hello" {
} return false
}
return true
}, "failed to parse extra string")
if float64(evt.GetExtra("elet").(int)) != evt.GetExtraNumber("elet") || evt.GetExtraNumber("elet") != 77 { assert.Condition(t, func() (success bool) {
t.Logf("number: %v == %v", evt.GetExtra("elet"), evt.GetExtraNumber("elet")) if float64(evt.GetExtra("elet").(int)) != evt.GetExtraNumber("elet") || evt.GetExtraNumber("elet") != 77 {
t.Errorf("failed to parse extra number") return false
} }
return true
}, "failed to parse extra number")
if evt.GetExtra("glub").(bool) != evt.GetExtraBoolean("glub") || evt.GetExtraBoolean("glub") != true { assert.Condition(t, func() (success bool) {
t.Errorf("failed to parse extra boolean") if evt.GetExtra("glub").(bool) != evt.GetExtraBoolean("glub") || evt.GetExtraBoolean("glub") != true {
}
if evt.GetExtra("plik") != nil { return false
t.Errorf("failed to parse extra null") }
} return true
}, "failed to parse extra boolean")
assert.Nil(t, evt.GetExtra("plik"))
} }
func mustSignEvent(t *testing.T, privkey string, event *Event) { func mustSignEvent(t *testing.T, privkey string, event *Event) {

View File

@ -4,21 +4,25 @@ import (
"encoding/json" "encoding/json"
"slices" "slices"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestFilterUnmarshal(t *testing.T) { func TestFilterUnmarshal(t *testing.T) {
raw := `{"ids": ["abc"],"#e":["zzz"],"#something":["nothing","bab"],"since":1644254609,"search":"test"}` raw := `{"ids": ["abc"],"#e":["zzz"],"#something":["nothing","bab"],"since":1644254609,"search":"test"}`
var f Filter var f Filter
if err := json.Unmarshal([]byte(raw), &f); err != nil { err := json.Unmarshal([]byte(raw), &f)
t.Errorf("failed to parse filter json: %v", err) assert.NoError(t, err)
}
if f.Since == nil || f.Since.Time().UTC().Format("2006-01-02") != "2022-02-07" || assert.Condition(t, func() (success bool) {
f.Until != nil || if f.Since == nil || f.Since.Time().UTC().Format("2006-01-02") != "2022-02-07" ||
f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") || f.Until != nil ||
f.Search != "test" { f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") ||
t.Error("failed to parse filter correctly") f.Search != "test" {
} return false
}
return true
}, "failed to parse filter correctly")
} }
func TestFilterMarshal(t *testing.T) { func TestFilterMarshal(t *testing.T) {
@ -28,31 +32,29 @@ func TestFilterMarshal(t *testing.T) {
Tags: TagMap{"fruit": {"banana", "mango"}}, Tags: TagMap{"fruit": {"banana", "mango"}},
Until: &until, Until: &until,
}) })
if err != nil { assert.NoError(t, err)
t.Errorf("failed to marshal filter json: %v", err)
}
expected := `{"kinds":[1,2,4],"until":12345678,"#fruit":["banana","mango"]}` expected := `{"kinds":[1,2,4],"until":12345678,"#fruit":["banana","mango"]}`
if string(filterj) != expected { assert.Equal(t, expected, string(filterj))
t.Errorf("filter json was wrong: %s != %s", string(filterj), expected)
}
} }
func TestFilterUnmarshalWithLimitZero(t *testing.T) { func TestFilterUnmarshalWithLimitZero(t *testing.T) {
raw := `{"ids": ["abc"],"#e":["zzz"],"limit":0,"#something":["nothing","bab"],"since":1644254609,"search":"test"}` raw := `{"ids": ["abc"],"#e":["zzz"],"limit":0,"#something":["nothing","bab"],"since":1644254609,"search":"test"}`
var f Filter var f Filter
if err := json.Unmarshal([]byte(raw), &f); err != nil { err := json.Unmarshal([]byte(raw), &f)
t.Errorf("failed to parse filter json: %v", err) assert.NoError(t, err)
}
if f.Since == nil || assert.Condition(t, func() (success bool) {
f.Since.Time().UTC().Format("2006-01-02") != "2022-02-07" || if f.Since == nil ||
f.Until != nil || f.Since.Time().UTC().Format("2006-01-02") != "2022-02-07" ||
f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") || f.Until != nil ||
f.Search != "test" || f.Tags == nil || len(f.Tags) != 2 || !slices.Contains(f.Tags["something"], "bab") ||
f.LimitZero == false { f.Search != "test" ||
t.Error("failed to parse filter correctly") f.LimitZero == false {
} return false
}
return true
}, "failed to parse filter correctly")
} }
func TestFilterMarshalWithLimitZero(t *testing.T) { func TestFilterMarshalWithLimitZero(t *testing.T) {
@ -63,14 +65,10 @@ func TestFilterMarshalWithLimitZero(t *testing.T) {
Until: &until, Until: &until,
LimitZero: true, LimitZero: true,
}) })
if err != nil { assert.NoError(t, err)
t.Errorf("failed to marshal filter json: %v", err)
}
expected := `{"kinds":[1,2,4],"until":12345678,"limit":0,"#fruit":["banana","mango"]}` expected := `{"kinds":[1,2,4],"until":12345678,"limit":0,"#fruit":["banana","mango"]}`
if string(filterj) != expected { assert.Equal(t, expected, string(filterj))
t.Errorf("filter json was wrong: %s != %s", string(filterj), expected)
}
} }
func TestFilterMatchingLive(t *testing.T) { func TestFilterMatchingLive(t *testing.T) {
@ -80,28 +78,22 @@ func TestFilterMatchingLive(t *testing.T) {
json.Unmarshal([]byte(`{"kinds":[1],"authors":["a8171781fd9e90ede3ea44ddca5d3abf828fe8eedeb0f3abb0dd3e563562e1fc","1d80e5588de010d137a67c42b03717595f5f510e73e42cfc48f31bae91844d59","ed4ca520e9929dfe9efdadf4011b53d30afd0678a09aa026927e60e7a45d9244"],"since":1677033299}`), &filter) json.Unmarshal([]byte(`{"kinds":[1],"authors":["a8171781fd9e90ede3ea44ddca5d3abf828fe8eedeb0f3abb0dd3e563562e1fc","1d80e5588de010d137a67c42b03717595f5f510e73e42cfc48f31bae91844d59","ed4ca520e9929dfe9efdadf4011b53d30afd0678a09aa026927e60e7a45d9244"],"since":1677033299}`), &filter)
json.Unmarshal([]byte(`{"id":"5a127c9c931f392f6afc7fdb74e8be01c34035314735a6b97d2cf360d13cfb94","pubkey":"1d80e5588de010d137a67c42b03717595f5f510e73e42cfc48f31bae91844d59","created_at":1677033299,"kind":1,"tags":[["t","japan"]],"content":"If you like my art,I'd appreciate a coin or two!!\nZap is welcome!! Thanks.\n\n\n#japan #bitcoin #art #bananaart\nhttps://void.cat/d/CgM1bzDgHUCtiNNwfX9ajY.webp","sig":"828497508487ca1e374f6b4f2bba7487bc09fccd5cc0d1baa82846a944f8c5766918abf5878a580f1e6615de91f5b57a32e34c42ee2747c983aaf47dbf2a0255"}`), &event) json.Unmarshal([]byte(`{"id":"5a127c9c931f392f6afc7fdb74e8be01c34035314735a6b97d2cf360d13cfb94","pubkey":"1d80e5588de010d137a67c42b03717595f5f510e73e42cfc48f31bae91844d59","created_at":1677033299,"kind":1,"tags":[["t","japan"]],"content":"If you like my art,I'd appreciate a coin or two!!\nZap is welcome!! Thanks.\n\n\n#japan #bitcoin #art #bananaart\nhttps://void.cat/d/CgM1bzDgHUCtiNNwfX9ajY.webp","sig":"828497508487ca1e374f6b4f2bba7487bc09fccd5cc0d1baa82846a944f8c5766918abf5878a580f1e6615de91f5b57a32e34c42ee2747c983aaf47dbf2a0255"}`), &event)
if !filter.Matches(&event) { assert.True(t, filter.Matches(&event), "live filter should match")
t.Error("live filter should match")
}
} }
func TestFilterEquality(t *testing.T) { func TestFilterEquality(t *testing.T) {
if !FilterEqual( assert.True(t, FilterEqual(
Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}}, Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}},
Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}}, Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}},
) { ), "kinds filters should be equal")
t.Error("kinds filters should be equal")
}
if !FilterEqual( assert.True(t, FilterEqual(
Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}, Tags: TagMap{"letter": {"a", "b"}}}, Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}, Tags: TagMap{"letter": {"a", "b"}}},
Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}, Tags: TagMap{"letter": {"b", "a"}}}, Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion}, Tags: TagMap{"letter": {"b", "a"}}},
) { ), "kind+tags filters should be equal")
t.Error("kind+tags filters should be equal")
}
tm := Now() tm := Now()
if !FilterEqual( assert.True(t, FilterEqual(
Filter{ Filter{
Kinds: []int{KindEncryptedDirectMessage, KindDeletion}, Kinds: []int{KindEncryptedDirectMessage, KindDeletion},
Tags: TagMap{"letter": {"a", "b"}, "fruit": {"banana"}}, Tags: TagMap{"letter": {"a", "b"}, "fruit": {"banana"}},
@ -114,16 +106,12 @@ func TestFilterEquality(t *testing.T) {
Since: &tm, Since: &tm,
IDs: []string{"aaaa", "bbbb"}, IDs: []string{"aaaa", "bbbb"},
}, },
) { ), "kind+2tags+since+ids filters should be equal")
t.Error("kind+2tags+since+ids filters should be equal")
}
if FilterEqual( assert.False(t, FilterEqual(
Filter{Kinds: []int{KindTextNote, KindEncryptedDirectMessage, KindDeletion}}, Filter{Kinds: []int{KindTextNote, KindEncryptedDirectMessage, KindDeletion}},
Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion, KindRepost}}, Filter{Kinds: []int{KindEncryptedDirectMessage, KindDeletion, KindRepost}},
) { ), "kinds filters shouldn't be equal")
t.Error("kinds filters shouldn't be equal")
}
} }
func TestFilterClone(t *testing.T) { func TestFilterClone(t *testing.T) {
@ -135,31 +123,21 @@ func TestFilterClone(t *testing.T) {
IDs: []string{"9894b4b5cb5166d23ee8899a4151cf0c66aec00bde101982a13b8e8ceb972df9"}, IDs: []string{"9894b4b5cb5166d23ee8899a4151cf0c66aec00bde101982a13b8e8ceb972df9"},
} }
clone := flt.Clone() clone := flt.Clone()
if !FilterEqual(flt, clone) { assert.True(t, FilterEqual(flt, clone), "clone is not equal:\n %v !=\n %v", flt, clone)
t.Errorf("clone is not equal:\n %v !=\n %v", flt, clone)
}
clone1 := flt.Clone() clone1 := flt.Clone()
clone1.IDs = append(clone1.IDs, "88f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") clone1.IDs = append(clone1.IDs, "88f0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")
if FilterEqual(flt, clone1) { assert.False(t, FilterEqual(flt, clone1), "modifying the clone ids should cause it to not be equal anymore")
t.Error("modifying the clone ids should cause it to not be equal anymore")
}
clone2 := flt.Clone() clone2 := flt.Clone()
clone2.Tags["letter"] = append(clone2.Tags["letter"], "c") clone2.Tags["letter"] = append(clone2.Tags["letter"], "c")
if FilterEqual(flt, clone2) { assert.False(t, FilterEqual(flt, clone2), "modifying the clone tag items should cause it to not be equal anymore")
t.Error("modifying the clone tag items should cause it to not be equal anymore")
}
clone3 := flt.Clone() clone3 := flt.Clone()
clone3.Tags["g"] = []string{"drt"} clone3.Tags["g"] = []string{"drt"}
if FilterEqual(flt, clone3) { assert.False(t, FilterEqual(flt, clone3), "modifying the clone tag map should cause it to not be equal anymore")
t.Error("modifying the clone tag map should cause it to not be equal anymore")
}
clone4 := flt.Clone() clone4 := flt.Clone()
*clone4.Since++ *clone4.Since++
if FilterEqual(flt, clone4) { assert.False(t, FilterEqual(flt, clone4), "modifying the clone since should cause it to not be equal anymore")
t.Error("modifying the clone since should cause it to not be equal anymore")
}
} }

4
go.mod
View File

@ -1,6 +1,6 @@
module github.com/nbd-wtf/go-nostr module github.com/nbd-wtf/go-nostr
go 1.21 go 1.22.5
require ( require (
github.com/bluekeyes/go-gitdiff v0.7.1 github.com/bluekeyes/go-gitdiff v0.7.1
@ -10,7 +10,7 @@ require (
github.com/gobwas/ws v1.2.0 github.com/gobwas/ws v1.2.0
github.com/mailru/easyjson v0.7.7 github.com/mailru/easyjson v0.7.7
github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/puzpuzpuz/xsync/v3 v3.0.2
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.14.4 github.com/tidwall/gjson v1.14.4
github.com/tyler-smith/go-bip32 v1.0.0 github.com/tyler-smith/go-bip32 v1.0.0
github.com/tyler-smith/go-bip39 v1.1.0 github.com/tyler-smith/go-bip39 v1.1.0

2
go.sum
View File

@ -92,6 +92,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=

View File

@ -3,48 +3,54 @@ package nip05
import ( import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
name, domain, _ := ParseIdentifier("saknd@yyq.com") tests := []struct {
if name != "saknd" || domain != "yyq.com" { input string
t.Fatalf("wrong parsing") expectedName string
expectedDomain string
expectError bool
}{
{"saknd@yyq.com", "saknd", "yyq.com", false},
{"287354gkj+asbdfo8gw3rlicbsopifbcp3iougb5piseubfdikswub5ks@yyq.com", "287354gkj+asbdfo8gw3rlicbsopifbcp3iougb5piseubfdikswub5ks", "yyq.com", false},
{"asdn.com", "_", "asdn.com", false},
{"_@uxux.com.br", "_", "uxux.com.br", false},
{"821yh498ig21", "", "", true},
{"////", "", "", true},
} }
name, domain, _ = ParseIdentifier("287354gkj+asbdfo8gw3rlicbsopifbcp3iougb5piseubfdikswub5ks@yyq.com") for _, test := range tests {
if name != "287354gkj+asbdfo8gw3rlicbsopifbcp3iougb5piseubfdikswub5ks" || domain != "yyq.com" { name, domain, err := ParseIdentifier(test.input)
t.Fatalf("wrong parsing") if test.expectError {
} assert.Error(t, err, "expected error for input: %s", test.input)
} else {
name, domain, _ = ParseIdentifier("asdn.com") assert.NoError(t, err, "not expect error for input: %s", test.input)
if name != "_" || domain != "asdn.com" { assert.Equal(t, test.expectedName, name)
t.Fatalf("wrong parsing") assert.Equal(t, test.expectedDomain, domain)
} }
name, domain, _ = ParseIdentifier("_@uxux.com.br")
if name != "_" || domain != "uxux.com.br" {
t.Fatalf("wrong parsing")
}
_, _, err := ParseIdentifier("821yh498ig21")
if err == nil {
t.Fatalf("should have errored")
}
_, _, err = ParseIdentifier("////")
if err == nil {
t.Fatalf("should have errored")
} }
} }
func TestQuery(t *testing.T) { func TestQuery(t *testing.T) {
pp, err := QueryIdentifier(context.Background(), "fiatjaf.com") tests := []struct {
if err != nil || pp.PublicKey != "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" { input string
t.Fatalf("invalid query for fiatjaf.com") expectedKey string
expectError bool
}{
{"fiatjaf.com", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", false},
{"htlc@fiatjaf.com", "f9dd6a762506260b38a2d3e5b464213c2e47fa3877429fe9ee60e071a31a07d7", false},
} }
pp, err = QueryIdentifier(context.Background(), "htlc@fiatjaf.com") for _, test := range tests {
if err != nil || pp.PublicKey != "f9dd6a762506260b38a2d3e5b464213c2e47fa3877429fe9ee60e071a31a07d7" { pp, err := QueryIdentifier(context.Background(), test.input)
t.Fatalf("invalid query for htlc@fiatjaf.com") if test.expectError {
assert.Error(t, err, "Expected error for input: %s", test.input)
} else {
assert.NoError(t, err, "Did not expect error for input: %s", test.input)
assert.Equal(t, test.expectedKey, pp.PublicKey, "For input: %s", test.input)
}
} }
} }

View File

@ -26,30 +26,35 @@ func TestAddSupportedNIP(t *testing.T) {
info.AddSupportedNIP(18) info.AddSupportedNIP(18)
for i, v := range []int{0, 1, 2, 12, 13, 17, 18, 19, 44} { for i, v := range []int{0, 1, 2, 12, 13, 17, 18, 19, 44} {
if info.SupportedNIPs[i] != v { assert.Equal(t, v, info.SupportedNIPs[i], "expected info.SupportedNIPs[%d] to equal %v, got %v",
t.Errorf("expected info.SupportedNIPs[%d] to equal %v, got %v", i, v, info.SupportedNIPs)
i, v, info.SupportedNIPs)
return
}
} }
} }
func TestFetch(t *testing.T) { func TestFetch(t *testing.T) {
res, err := Fetch(context.Background(), "wss://relay.nostr.bg") tests := []struct {
assert.Equal(t, res.URL, "wss://relay.nostr.bg") inputURL string
assert.Nil(t, err, "failed to fetch from wss") expectError bool
assert.NotEmpty(t, res.Name) expectedName string
expectedURL string
}{
{"wss://relay.nostr.bg", false, "", "wss://relay.nostr.bg"},
{"https://relay.nostr.bg", false, "", "wss://relay.nostr.bg"},
{"relay.nostr.bg", false, "", "wss://relay.nostr.bg"},
{"wlenwqkeqwe.asjdaskd", true, "", "wss://wlenwqkeqwe.asjdaskd"},
}
res, err = Fetch(context.Background(), "https://relay.nostr.bg") for _, test := range tests {
assert.Nil(t, err, "failed to fetch from https") res, err := Fetch(context.Background(), test.inputURL)
assert.NotEmpty(t, res.Name)
res, err = Fetch(context.Background(), "relay.nostr.bg") if test.expectError {
assert.Nil(t, err, "failed to fetch without protocol") assert.Error(t, err, "expected error for URL: %s", test.inputURL)
assert.NotEmpty(t, res.Name) assert.NotNil(t, res, "expected result not to be nil for URL: %s", test.inputURL)
assert.Equal(t, test.expectedURL, res.URL, "expected URL to be %s for input: %s", test.expectedURL, test.inputURL)
res, err = Fetch(context.Background(), "wlenwqkeqwe.asjdaskd") } else {
assert.Error(t, err) assert.Nil(t, err, "unexpect error for URL: %s", test.inputURL)
assert.NotNil(t, res) assert.NotEmpty(t, res.Name, "expected non-empty name for URL: %s", test.inputURL)
assert.Equal(t, res.URL, "wss://wlenwqkeqwe.asjdaskd") assert.Equal(t, test.expectedURL, res.URL, "expected URL to be %s for input: %s", test.expectedURL, test.inputURL)
}
}
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
) )
// Deprecated: use DoWork() // Deprecated: use DoWork() instead.
func Generate(event *nostr.Event, targetDifficulty int, timeout time.Duration) (*nostr.Event, error) { func Generate(event *nostr.Event, targetDifficulty int, timeout time.Duration) (*nostr.Event, error) {
if event.PubKey == "" { if event.PubKey == "" {
return nil, ErrMissingPubKey return nil, ErrMissingPubKey

View File

@ -4,96 +4,61 @@ import (
"testing" "testing"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/stretchr/testify/assert"
) )
func TestEncodeNpub(t *testing.T) { func TestEncodeNpub(t *testing.T) {
npub, err := EncodePublicKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") npub, err := EncodePublicKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")
if err != nil { assert.NoError(t, err)
t.Errorf("shouldn't error: %s", err) assert.Equal(t, "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6", npub, "produced an unexpected npub string")
}
if npub != "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6" {
t.Error("produced an unexpected npub string")
}
} }
func TestEncodeNsec(t *testing.T) { func TestEncodeNsec(t *testing.T) {
nsec, err := EncodePrivateKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") nsec, err := EncodePrivateKey("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")
if err != nil { assert.NoError(t, err)
t.Errorf("shouldn't error: %s", err) assert.Equal(t, "nsec180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsgyumg0", nsec, "produced an unexpected nsec string")
}
if nsec != "nsec180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsgyumg0" {
t.Error("produced an unexpected nsec string")
}
} }
func TestDecodeNpub(t *testing.T) { func TestDecodeNpub(t *testing.T) {
prefix, pubkey, err := Decode("npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6") prefix, pubkey, err := Decode("npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6")
if err != nil { assert.NoError(t, err)
t.Errorf("shouldn't error: %s", err) assert.Equal(t, "npub", prefix, "returned invalid prefix")
} assert.Equal(t, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", pubkey.(string), "returned wrong pubkey")
if prefix != "npub" {
t.Error("returned invalid prefix")
}
if pubkey.(string) != "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" {
t.Error("returned wrong pubkey")
}
} }
func TestFailDecodeBadChecksumNpub(t *testing.T) { func TestFailDecodeBadChecksumNpub(t *testing.T) {
_, _, err := Decode("npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w4") _, _, err := Decode("npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w4")
if err == nil { assert.Error(t, err)
t.Errorf("should have errored: %s", err)
}
} }
func TestDecodeNprofile(t *testing.T) { func TestDecodeNprofile(t *testing.T) {
prefix, data, err := Decode("nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p") t.Run("first", func(t *testing.T) {
if err != nil { prefix, data, err := Decode("nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p")
t.Error("failed to decode nprofile") assert.NoError(t, err)
} assert.Equal(t, "nprofile", prefix)
if prefix != "nprofile" {
t.Error("what")
}
pp, ok := data.(nostr.ProfilePointer)
if !ok {
t.Error("value returned of wrong type")
}
if pp.PublicKey != "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" { pp, ok := data.(nostr.ProfilePointer)
t.Error("decoded invalid public key") assert.True(t, ok, "value returned of wrong type")
} assert.Equal(t, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", pp.PublicKey)
assert.Equal(t, 2, len(pp.Relays), "decoded wrong number of relays")
if len(pp.Relays) != 2 { assert.Equal(t, "wss://r.x.com", pp.Relays[0], "decoded relay URLs wrongly")
t.Error("decoded wrong number of relays") assert.Equal(t, "wss://djbas.sadkb.com", pp.Relays[1], "decoded relay URLs wrongly")
} })
if pp.Relays[0] != "wss://r.x.com" || pp.Relays[1] != "wss://djbas.sadkb.com" {
t.Error("decoded relay URLs wrongly")
}
}
func TestDecodeOtherNprofile(t *testing.T) { t.Run("second", func(t *testing.T) {
prefix, data, err := Decode("nprofile1qqsw3dy8cpumpanud9dwd3xz254y0uu2m739x0x9jf4a9sgzjshaedcpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5qyw8wumn8ghj7mn0wd68yttjv4kxz7fww4h8get5dpezumt9qyvhwumn8ghj7un9d3shjetj9enxjct5dfskvtnrdakstl69hg") prefix, data, err := Decode("nprofile1qqsw3dy8cpumpanud9dwd3xz254y0uu2m739x0x9jf4a9sgzjshaedcpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5qyw8wumn8ghj7mn0wd68yttjv4kxz7fww4h8get5dpezumt9qyvhwumn8ghj7un9d3shjetj9enxjct5dfskvtnrdakstl69hg")
if err != nil { assert.NoError(t, err)
t.Error("failed to decode nprofile") assert.Equal(t, "nprofile", prefix)
}
if prefix != "nprofile" {
t.Error("what")
}
pp, ok := data.(nostr.ProfilePointer)
if !ok {
t.Error("value returned of wrong type")
}
if pp.PublicKey != "e8b487c079b0f67c695ae6c4c2552a47f38adfa2533cc5926bd2c102942fdcb7" { pp, ok := data.(nostr.ProfilePointer)
t.Error("decoded invalid public key") assert.True(t, ok, "value returned of wrong type")
} assert.Equal(t, "e8b487c079b0f67c695ae6c4c2552a47f38adfa2533cc5926bd2c102942fdcb7", pp.PublicKey)
assert.Equal(t, 3, len(pp.Relays), "decoded wrong number of relays")
if len(pp.Relays) != 3 { assert.Equal(t, "wss://nostr-pub.wellorder.net", pp.Relays[0], "decoded relay URLs wrongly")
t.Error("decoded wrong number of relays") assert.Equal(t, "wss://nostr-relay.untethr.me", pp.Relays[1], "decoded relay URLs wrongly")
} })
if pp.Relays[0] != "wss://nostr-pub.wellorder.net" || pp.Relays[1] != "wss://nostr-relay.untethr.me" {
t.Error("decoded relay URLs wrongly")
}
} }
func TestEncodeNprofile(t *testing.T) { func TestEncodeNprofile(t *testing.T) {
@ -101,12 +66,11 @@ func TestEncodeNprofile(t *testing.T) {
"wss://r.x.com", "wss://r.x.com",
"wss://djbas.sadkb.com", "wss://djbas.sadkb.com",
}) })
if err != nil {
t.Errorf("shouldn't error: %s", err) assert.NoError(t, err)
} assert.Equal(t,
if nprofile != "nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p" { "nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p",
t.Error("produced an unexpected nprofile string") nprofile, "produced an unexpected nprofile string: %s", nprofile)
}
} }
func TestEncodeDecodeNaddr(t *testing.T) { func TestEncodeDecodeNaddr(t *testing.T) {
@ -118,91 +82,60 @@ func TestEncodeDecodeNaddr(t *testing.T) {
"wss://relay.nostr.example.mydomain.example.com", "wss://relay.nostr.example.mydomain.example.com",
"wss://nostr.banana.com", "wss://nostr.banana.com",
}) })
if err != nil {
t.Errorf("shouldn't error: %s", err) assert.NoError(t, err)
} assert.Equal(t,
if naddr != "naddr1qqrxyctwv9hxzqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmdqgsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8grqsqqqa28a3lkds" { "naddr1qqrxyctwv9hxzqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmdqgsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8grqsqqqa28a3lkds",
t.Errorf("produced an unexpected naddr string: %s", naddr) naddr, "produced an unexpected naddr string: %s", naddr)
}
prefix, data, err := Decode(naddr) prefix, data, err := Decode(naddr)
if err != nil { assert.NoError(t, err)
t.Errorf("shouldn't error: %s", err) assert.Equal(t, "naddr", prefix)
}
if prefix != "naddr" {
t.Error("returned invalid prefix")
}
ep := data.(nostr.EntityPointer) ep := data.(nostr.EntityPointer)
if ep.PublicKey != "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d" { assert.Equal(t, "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", ep.PublicKey)
t.Error("returned wrong pubkey") assert.Equal(t, ep.Kind, nostr.KindArticle)
} assert.Equal(t, "banana", ep.Identifier)
if ep.Kind != nostr.KindArticle {
t.Error("returned wrong kind") assert.Equal(t, "wss://relay.nostr.example.mydomain.example.com", ep.Relays[0])
} assert.Equal(t, "wss://nostr.banana.com", ep.Relays[1])
if ep.Identifier != "banana" {
t.Error("returned wrong identifier")
}
if ep.Relays[0] != "wss://relay.nostr.example.mydomain.example.com" || ep.Relays[1] != "wss://nostr.banana.com" {
t.Error("returned wrong relays")
}
} }
func TestDecodeNaddrWithoutRelays(t *testing.T) { func TestDecodeNaddrWithoutRelays(t *testing.T) {
prefix, data, err := Decode("naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5") prefix, data, err := Decode("naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5")
if err != nil { assert.NoError(t, err, "unexpected error during decoding of Naddr")
t.Errorf("shouldn't error: %s", err) assert.Equal(t, "naddr", prefix, "returned invalid prefix")
}
if prefix != "naddr" { ep, ok := data.(nostr.EntityPointer)
t.Error("returned invalid prefix") assert.True(t, ok)
} assert.Equal(t, "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", ep.PublicKey)
ep := data.(nostr.EntityPointer) assert.Equal(t, nostr.KindArticle, ep.Kind)
if ep.PublicKey != "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194" { assert.Equal(t, "references", ep.Identifier)
t.Error("returned wrong pubkey") assert.Empty(t, ep.Relays)
}
if ep.Kind != nostr.KindArticle {
t.Error("returned wrong kind")
}
if ep.Identifier != "references" {
t.Error("returned wrong identifier")
}
if len(ep.Relays) != 0 {
t.Error("relays should have been an empty array")
}
} }
func TestEncodeDecodeNEventTestEncodeDecodeNEvent(t *testing.T) { func TestEncodeDecodeNEvent(t *testing.T) {
nevent, err := EncodeEvent( nevent, err := EncodeEvent(
"45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", "45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194",
[]string{"wss://banana.com"}, []string{"wss://banana.com"},
"7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88", "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88",
) )
if err != nil {
t.Errorf("shouldn't error: %s", err) assert.NoError(t, err)
}
expectedNEvent := "nevent1qqsy2vn0t45k92c78n2zfe6ccvqzhpn977cd3h8wnl579zxhw5dvr9qpzpmhxue69uhkyctwv9hxztnrdaksygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2x4m3q04ndyp"
assert.Equal(t, expectedNEvent, nevent)
prefix, res, err := Decode(nevent) prefix, res, err := Decode(nevent)
if err != nil { assert.NoError(t, err)
t.Errorf("shouldn't error: %s", err)
}
if prefix != "nevent" { assert.Equal(t, "nevent", prefix)
t.Errorf("should have 'nevent' prefix, not '%s'", prefix)
}
ep, ok := res.(nostr.EventPointer) ep, ok := res.(nostr.EventPointer)
if !ok { assert.True(t, ok)
t.Errorf("'%s' should be an nevent, not %v", nevent, res)
}
if ep.Author != "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88" { assert.Equal(t, "7fa56f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751abb88", ep.Author)
t.Error("wrong author") assert.Equal(t, "45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194", ep.ID)
} assert.Equal(t, 1, len(ep.Relays), "wrong number of relays")
assert.Equal(t, "wss://banana.com", ep.Relays[0])
if ep.ID != "45326f5d6962ab1e3cd424e758c3002b8665f7b0d8dcee9fe9e288d7751ac194" {
t.Error("wrong id")
}
if len(ep.Relays) != 1 || ep.Relays[0] != "wss://banana.com" {
t.Error("wrong relay")
}
} }

View File

@ -2,6 +2,8 @@ package nip29
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
const ( const (
@ -16,11 +18,10 @@ func TestGroupEventBackAndForth(t *testing.T) {
group1.Name = "banana" group1.Name = "banana"
group1.Private = true group1.Private = true
meta1 := group1.ToMetadataEvent() meta1 := group1.ToMetadataEvent()
if meta1.Tags.GetD() != "xyz" ||
meta1.Tags.GetFirst([]string{"name", "banana"}) == nil || assert.Equal(t, "xyz", meta1.Tags.GetD(), "translation of group1 to metadata event failed: %s", meta1)
meta1.Tags.GetFirst([]string{"private"}) == nil { assert.NotNil(t, meta1.Tags.GetFirst([]string{"name", "banana"}), "translation of group1 to metadata event failed: %s", meta1)
t.Fatalf("translation of group1 to metadata event failed: %s", meta1) assert.NotNil(t, meta1.Tags.GetFirst([]string{"private"}), "translation of group1 to metadata event failed: %s", meta1)
}
group2, _ := NewGroup("groups.com'abc") group2, _ := NewGroup("groups.com'abc")
group2.Members[ALICE] = &Role{Name: "nada", Permissions: map[Permission]struct{}{PermAddUser: {}}} group2.Members[ALICE] = &Role{Name: "nada", Permissions: map[Permission]struct{}{PermAddUser: {}}}
@ -28,34 +29,31 @@ func TestGroupEventBackAndForth(t *testing.T) {
group2.Members[CAROL] = EmptyRole group2.Members[CAROL] = EmptyRole
group2.Members[DEREK] = EmptyRole group2.Members[DEREK] = EmptyRole
admins2 := group2.ToAdminsEvent() admins2 := group2.ToAdminsEvent()
if admins2.Tags.GetD() != "abc" ||
len(admins2.Tags) != 3 || assert.Equal(t, "abc", admins2.Tags.GetD(), "translation of group2 to admins event failed")
admins2.Tags.GetFirst([]string{"p", ALICE, "nada", "add-user"}) == nil || assert.Equal(t, 3, len(admins2.Tags), "translation of group2 to admins event failed")
admins2.Tags.GetFirst([]string{"p", BOB, "nada", "edit-metadata"}) == nil { assert.NotNil(t, admins2.Tags.GetFirst([]string{"p", ALICE, "nada", "add-user"}), "translation of group2 to admins event failed")
t.Fatalf("translation of group2 to admins event failed") assert.NotNil(t, admins2.Tags.GetFirst([]string{"p", BOB, "nada", "edit-metadata"}), "translation of group2 to admins event failed")
}
members2 := group2.ToMembersEvent() members2 := group2.ToMembersEvent()
if members2.Tags.GetD() != "abc" || assert.Equal(t, "abc", members2.Tags.GetD(), "translation of group2 to members2 event failed")
len(members2.Tags) != 5 || assert.Equal(t, 5, len(members2.Tags), "translation of group2 to members2 event failed")
members2.Tags.GetFirst([]string{"p", ALICE}) == nil || assert.NotNil(t, members2.Tags.GetFirst([]string{"p", ALICE}), "translation of group2 to members2 event failed")
members2.Tags.GetFirst([]string{"p", BOB}) == nil || assert.NotNil(t, members2.Tags.GetFirst([]string{"p", BOB}), "translation of group2 to members2 event failed")
members2.Tags.GetFirst([]string{"p", CAROL}) == nil || assert.NotNil(t, members2.Tags.GetFirst([]string{"p", CAROL}), "translation of group2 to members2 event failed")
members2.Tags.GetFirst([]string{"p", DEREK}) == nil { assert.NotNil(t, members2.Tags.GetFirst([]string{"p", DEREK}), "translation of group2 to members2 event failed")
t.Fatalf("translation of group2 to members2 event failed")
}
group1.MergeInMembersEvent(members2) group1.MergeInMembersEvent(members2)
if len(group1.Members) != 4 || group1.Members[ALICE] != EmptyRole || group1.Members[DEREK] != EmptyRole { assert.Equal(t, 4, len(group1.Members), "merge of members2 into group1 failed")
t.Fatalf("merge of members2 into group1 failed") assert.Equal(t, EmptyRole, group1.Members[ALICE], "merge of members2 into group1 failed")
} assert.Equal(t, EmptyRole, group1.Members[DEREK], "merge of members2 into group1 failed")
group1.MergeInAdminsEvent(admins2) group1.MergeInAdminsEvent(admins2)
if len(group1.Members) != 4 || group1.Members[ALICE].Name != "nada" || group1.Members[DEREK] != EmptyRole { assert.Equal(t, 4, len(group1.Members), "merge of admins2 into group1 failed")
t.Fatalf("merge of admins2 into group1 failed") assert.Equal(t, "nada", group1.Members[ALICE].Name, "merge of admins2 into group1 failed")
} assert.Equal(t, EmptyRole, group1.Members[DEREK], "merge of admins2 into group1 failed")
group2.MergeInMetadataEvent(meta1) group2.MergeInMetadataEvent(meta1)
if group2.Name != "banana" || group2.Address.ID != "abc" { assert.Equal(t, "banana", group2.Name, "merge of meta1 into group2 failed")
t.Fatalf("merge of meta1 into group2 failed") assert.Equal(t, "abc", group2.Address.ID, "merge of meta1 into group2 failed")
}
} }

View File

@ -47,7 +47,7 @@ func assertCryptPriv(t *testing.T, sk1 string, sk2 string, conversationKey strin
assert.Equal(t, decrypted, plaintext, "wrong decryption") assert.Equal(t, decrypted, plaintext, "wrong decryption")
} }
func assertDecryptFail(t *testing.T, conversationKey string, plaintext string, ciphertext string, msg string) { func assertDecryptFail(t *testing.T, conversationKey string, _ string, ciphertext string, msg string) {
var ( var (
k1 []byte k1 []byte
ok bool ok bool

View File

@ -1,21 +1,24 @@
package nip46 package nip46
import "testing" import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestValidBunkerURL(t *testing.T) { func TestValidBunkerURL(t *testing.T) {
if !IsValidBunkerURL("bunker://3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.snort.social&relay=wss%3A%2F%2Frelay.nsecbunker.com") { valid := IsValidBunkerURL("bunker://3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.snort.social&relay=wss%3A%2F%2Frelay.nsecbunker.com")
t.Fatalf("should be valid") assert.True(t, valid, "should be valid")
}
if IsValidBunkerURL("askjdbkajdbv") { inValid := IsValidBunkerURL("askjdbkajdbv")
t.Fatalf("should be invalid") assert.False(t, inValid, "should be invalid")
}
if IsValidBunkerURL("asdjasbndksa@asjdnksa.com") { inValid1 := IsValidBunkerURL("asdjasbndksa@asjdnksa.com")
t.Fatalf("should be invalid") assert.False(t, inValid1, "should be invalid")
}
if IsValidBunkerURL("https://hello.com?relays=wss://xxxxxx.xxxx") { inValid2 := IsValidBunkerURL("https://hello.com?relays=wss://xxxxxx.xxxx")
t.Fatalf("should be invalid") assert.False(t, inValid2, "should be invalid")
}
if IsValidBunkerURL("bunker://fa883d107ef9e558472c4eb9aaaefa459d?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.snort.social&relay=wss%3A%2F%2Frelay.nsecbunker.com") { inValid3 := IsValidBunkerURL("bunker://fa883d107ef9e558472c4eb9aaaefa459d?relay=wss%3A%2F%2Frelay.damus.io&relay=wss%3A%2F%2Frelay.snort.social&relay=wss%3A%2F%2Frelay.nsecbunker.com")
t.Fatalf("should be invalid") assert.False(t, inValid3, "should be invalid")
}
} }

View File

@ -5,17 +5,15 @@ import (
"slices" "slices"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestDecryptKeyFromNIPText(t *testing.T) { func TestDecryptKeyFromNIPText(t *testing.T) {
ncrypt := "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p" ncrypt := "ncryptsec1qgg9947rlpvqu76pj5ecreduf9jxhselq2nae2kghhvd5g7dgjtcxfqtd67p9m0w57lspw8gsq6yphnm8623nsl8xn9j4jdzz84zm3frztj3z7s35vpzmqf6ksu8r89qk5z2zxfmu5gv8th8wclt0h4p"
secretKey, err := Decrypt(ncrypt, "nostr") secretKey, err := Decrypt(ncrypt, "nostr")
if err != nil { assert.NoError(t, err)
t.Fatalf("failed to decrypt: %s", err) assert.Equal(t, "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683", secretKey)
}
if secretKey != "3501454135014541350145413501453fefb02227e449e57cf4d3a3ce05378683" {
t.Fatalf("decrypted wrongly: %s", secretKey)
}
} }
func TestEncryptAndDecrypt(t *testing.T) { func TestEncryptAndDecrypt(t *testing.T) {
@ -38,20 +36,13 @@ func TestEncryptAndDecrypt(t *testing.T) {
{"ÅΩṩ", "11b25a101667dd9208db93c0827c6bdad66729a5b521156a7e9d3b22b3ae8944", 9, 0x01}, {"ÅΩṩ", "11b25a101667dd9208db93c0827c6bdad66729a5b521156a7e9d3b22b3ae8944", 9, 0x01},
} { } {
bech32code, err := Encrypt(f.secretkey, f.password, f.logn, f.ksb) bech32code, err := Encrypt(f.secretkey, f.password, f.logn, f.ksb)
if err != nil { assert.NoError(t, err)
t.Fatalf("failed to encrypt %d: %s", i, err) assert.True(t, strings.HasPrefix(bech32code, "ncryptsec1"), "bech32 code is wrong %d: %s", i, bech32code)
} assert.Equal(t, 162, len(bech32code), "bech32 code is wrong %d: %s", i, bech32code)
if !strings.HasPrefix(bech32code, "ncryptsec1") || len(bech32code) != 162 {
t.Fatalf("bech32 code is wrong %d: %s", i, bech32code)
}
secretKey, err := Decrypt(bech32code, f.password) secretKey, err := Decrypt(bech32code, f.password)
if err != nil { assert.NoError(t, err)
t.Fatalf("failed to decrypt %d: %s", i, err) assert.Equal(t, f.secretkey, secretKey)
}
if secretKey != f.secretkey {
t.Fatalf("decrypted to the wrong value %d: %s", i, secretKey)
}
} }
} }
@ -62,13 +53,9 @@ func TestNormalization(t *testing.T) {
key2, err2 := getKey(string([]byte{0xC3, 0x85, 0xCE, 0xA9, 0xE1, 0xB9, 0xA9}), nonce, n) key2, err2 := getKey(string([]byte{0xC3, 0x85, 0xCE, 0xA9, 0xE1, 0xB9, 0xA9}), nonce, n)
key3, err3 := getKey("ÅΩẛ̣", nonce, n) key3, err3 := getKey("ÅΩẛ̣", nonce, n)
key4, err4 := getKey("ÅΩẛ̣", nonce, n) key4, err4 := getKey("ÅΩẛ̣", nonce, n)
if merr := errors.Join(err1, err2, err3, err4); merr != nil { err := errors.Join(err1, err2, err3, err4)
t.Fatalf("getKey errored: %s", merr) assert.NoError(t, err)
return assert.True(t, slices.Equal(key1, key2), "normalization failed")
} assert.True(t, slices.Equal(key2, key3), "normalization failed")
assert.True(t, slices.Equal(key3, key4), "normalization failed")
if !slices.Equal(key1, key2) || !slices.Equal(key2, key3) || !slices.Equal(key3, key4) {
t.Fatalf("normalization failed")
return
}
} }

View File

@ -6,10 +6,14 @@ import (
"testing" "testing"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestUpload(t *testing.T) { func TestUpload(t *testing.T) {
img, _ := os.Open("./testdata/image.png") img, err := os.Open("./testdata/image.png")
require.NoError(t, err)
defer img.Close() defer img.Close()
ctx := context.Background() ctx := context.Background()
@ -24,9 +28,7 @@ func TestUpload(t *testing.T) {
ContentType: "image/png", ContentType: "image/png",
NoTransform: true, NoTransform: true,
}) })
if err != nil { assert.NoError(t, err)
t.Fatal(err, "client.Upload")
}
t.Logf("resp: %#v\n", *resp) t.Logf("resp: %#v\n", *resp)
// nip96_test.go:28: resp: nip96.UploadResponse{Status:"success", Message:"Upload successful.", ProcessingURL:"", Nip94Event:struct { Tags nostr.Tags "json:\"tags\"" }{Tags:nostr.Tags{nostr.Tag{"url", "https://image.nostr.build/4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673.jpg"}, nostr.Tag{"ox", "4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673"}, nostr.Tag{"x", ""}, nostr.Tag{"m", "image/jpeg"}, nostr.Tag{"dim", "1125x750"}, nostr.Tag{"bh", "LLF=kB-;yH-;-;R#t7xKEZWA#_oM"}, nostr.Tag{"blurhash", "LLF=kB-;yH-;-;R#t7xKEZWA#_oM"}, nostr.Tag{"thumb", "https://image.nostr.build/thumb/4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673.jpg"}}}} // nip96_test.go:28: resp: nip96.UploadResponse{Status:"success", Message:"Upload successful.", ProcessingURL:"", Nip94Event:struct { Tags nostr.Tags "json:\"tags\"" }{Tags:nostr.Tags{nostr.Tag{"url", "https://image.nostr.build/4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673.jpg"}, nostr.Tag{"ox", "4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673"}, nostr.Tag{"x", ""}, nostr.Tag{"m", "image/jpeg"}, nostr.Tag{"dim", "1125x750"}, nostr.Tag{"bh", "LLF=kB-;yH-;-;R#t7xKEZWA#_oM"}, nostr.Tag{"blurhash", "LLF=kB-;yH-;-;R#t7xKEZWA#_oM"}, nostr.Tag{"thumb", "https://image.nostr.build/thumb/4ece05f1d77c9cb97d334ba9c0301b2960640df89bf5d75d6bffadefc4355673.jpg"}}}}

View File

@ -2,6 +2,8 @@ package nostr
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
type urlTest struct { type urlTest struct {
@ -29,8 +31,7 @@ var urlTests = []urlTest{
func TestNormalizeURL(t *testing.T) { func TestNormalizeURL(t *testing.T) {
for _, test := range urlTests { for _, test := range urlTests {
if output := NormalizeURL(test.url); output != test.expected { output := NormalizeURL(test.url)
t.Errorf("Output '%s' not equal to expected '%s'", output, test.expected) assert.Equal(t, test.expected, output)
}
} }
} }

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"io" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -12,6 +11,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
@ -25,9 +26,8 @@ func TestPublish(t *testing.T) {
Tags: Tags{[]string{"foo", "bar"}}, Tags: Tags{[]string{"foo", "bar"}},
PubKey: pub, PubKey: pub,
} }
if err := textNote.Sign(priv); err != nil { err := textNote.Sign(priv)
t.Fatalf("textNote.Sign: %v", err) assert.NoError(t, err)
}
// fake relay server // fake relay server
var mu sync.Mutex // guards published to satisfy go test -race var mu sync.Mutex // guards published to satisfy go test -race
@ -38,30 +38,25 @@ func TestPublish(t *testing.T) {
mu.Unlock() mu.Unlock()
// verify the client sent exactly the textNote // verify the client sent exactly the textNote
var raw []json.RawMessage var raw []json.RawMessage
if err := websocket.JSON.Receive(conn, &raw); err != nil { err := websocket.JSON.Receive(conn, &raw)
t.Errorf("websocket.JSON.Receive: %v", err) assert.NoError(t, err)
}
event := parseEventMessage(t, raw) event := parseEventMessage(t, raw)
if !bytes.Equal(event.Serialize(), textNote.Serialize()) { assert.True(t, bytes.Equal(event.Serialize(), textNote.Serialize()))
t.Errorf("received event:\n%+v\nwant:\n%+v", event, textNote)
}
// send back an ok nip-20 command result // send back an ok nip-20 command result
res := []any{"OK", textNote.ID, true, ""} res := []any{"OK", textNote.ID, true, ""}
if err := websocket.JSON.Send(conn, res); err != nil { err = websocket.JSON.Send(conn, res)
t.Errorf("websocket.JSON.Send: %v", err) assert.NoError(t, err)
}
}) })
defer ws.Close() defer ws.Close()
// connect a client and send the text note // connect a client and send the text note
rl := mustRelayConnect(ws.URL) rl := mustRelayConnect(t, ws.URL)
err := rl.Publish(context.Background(), textNote) err = rl.Publish(context.Background(), textNote)
if err != nil { assert.NoError(t, err)
t.Errorf("publish should have succeeded")
} assert.True(t, published, "fake relay server saw no event")
if !published {
t.Errorf("fake relay server saw no event")
}
} }
func TestPublishBlocked(t *testing.T) { func TestPublishBlocked(t *testing.T) {
@ -73,9 +68,9 @@ func TestPublishBlocked(t *testing.T) {
ws := newWebsocketServer(func(conn *websocket.Conn) { ws := newWebsocketServer(func(conn *websocket.Conn) {
// discard received message; not interested // discard received message; not interested
var raw []json.RawMessage var raw []json.RawMessage
if err := websocket.JSON.Receive(conn, &raw); err != nil { err := websocket.JSON.Receive(conn, &raw)
t.Errorf("websocket.JSON.Receive: %v", err) assert.NoError(t, err)
}
// send back a not ok nip-20 command result // send back a not ok nip-20 command result
res := []any{"OK", textNote.ID, false, "blocked"} res := []any{"OK", textNote.ID, false, "blocked"}
websocket.JSON.Send(conn, res) websocket.JSON.Send(conn, res)
@ -83,11 +78,9 @@ func TestPublishBlocked(t *testing.T) {
defer ws.Close() defer ws.Close()
// connect a client and send a text note // connect a client and send a text note
rl := mustRelayConnect(ws.URL) rl := mustRelayConnect(t, ws.URL)
err := rl.Publish(context.Background(), textNote) err := rl.Publish(context.Background(), textNote)
if err == nil { assert.Error(t, err)
t.Errorf("should have failed to publish")
}
} }
func TestPublishWriteFailed(t *testing.T) { func TestPublishWriteFailed(t *testing.T) {
@ -103,13 +96,11 @@ func TestPublishWriteFailed(t *testing.T) {
defer ws.Close() defer ws.Close()
// connect a client and send a text note // connect a client and send a text note
rl := mustRelayConnect(ws.URL) rl := mustRelayConnect(t, ws.URL)
// Force brief period of time so that publish always fails on closed socket. // Force brief period of time so that publish always fails on closed socket.
time.Sleep(1 * time.Millisecond) time.Sleep(1 * time.Millisecond)
err := rl.Publish(context.Background(), textNote) err := rl.Publish(context.Background(), textNote)
if err == nil { assert.Error(t, err)
t.Errorf("should have failed to publish")
}
} }
func TestConnectContext(t *testing.T) { func TestConnectContext(t *testing.T) {
@ -128,16 +119,13 @@ func TestConnectContext(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
r, err := RelayConnect(ctx, ws.URL) r, err := RelayConnect(ctx, ws.URL)
if err != nil { assert.NoError(t, err)
t.Fatalf("RelayConnectContext: %v", err)
}
defer r.Close() defer r.Close()
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
if !connected { assert.True(t, connected, "fake relay server saw no client connect")
t.Error("fake relay server saw no client connect")
}
} }
func TestConnectContextCanceled(t *testing.T) { func TestConnectContextCanceled(t *testing.T) {
@ -149,9 +137,7 @@ func TestConnectContextCanceled(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
cancel() // make ctx expired cancel() // make ctx expired
_, err := RelayConnect(ctx, ws.URL) _, err := RelayConnect(ctx, ws.URL)
if !errors.Is(err, context.Canceled) { assert.ErrorIs(t, err, context.Canceled)
t.Errorf("RelayConnectContext returned %v error; want context.Canceled", err)
}
} }
func TestConnectWithOrigin(t *testing.T) { func TestConnectWithOrigin(t *testing.T) {
@ -166,9 +152,7 @@ func TestConnectWithOrigin(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
err := r.Connect(ctx) err := r.Connect(ctx)
if err != nil { assert.NoError(t, err)
t.Errorf("unexpected error: %v", err)
}
} }
func discardingHandler(conn *websocket.Conn) { func discardingHandler(conn *websocket.Conn) {
@ -191,59 +175,62 @@ var anyOriginHandshake = func(conf *websocket.Config, r *http.Request) error {
func makeKeyPair(t *testing.T) (priv, pub string) { func makeKeyPair(t *testing.T) (priv, pub string) {
t.Helper() t.Helper()
privkey := GeneratePrivateKey() privkey := GeneratePrivateKey()
pubkey, err := GetPublicKey(privkey) pubkey, err := GetPublicKey(privkey)
if err != nil { assert.NoError(t, err)
t.Fatalf("GetPublicKey(%q): %v", privkey, err)
}
return privkey, pubkey return privkey, pubkey
} }
func mustRelayConnect(url string) *Relay { func mustRelayConnect(t *testing.T, url string) *Relay {
t.Helper()
rl, err := RelayConnect(context.Background(), url) rl, err := RelayConnect(context.Background(), url)
if err != nil { require.NoError(t, err)
panic(err.Error())
}
return rl return rl
} }
func parseEventMessage(t *testing.T, raw []json.RawMessage) Event { func parseEventMessage(t *testing.T, raw []json.RawMessage) Event {
t.Helper() t.Helper()
if len(raw) < 2 {
t.Fatalf("len(raw) = %d; want at least 2", len(raw)) assert.Condition(t, func() (success bool) {
} return len(raw) >= 2
})
var typ string var typ string
json.Unmarshal(raw[0], &typ) err := json.Unmarshal(raw[0], &typ)
if typ != "EVENT" { assert.NoError(t, err)
t.Errorf("typ = %q; want EVENT", typ) assert.Equal(t, "EVENT", typ)
}
var event Event var event Event
if err := json.Unmarshal(raw[1], &event); err != nil { err = json.Unmarshal(raw[1], &event)
t.Errorf("json.Unmarshal(`%s`): %v", string(raw[1]), err) require.NoError(t, err)
}
return event return event
} }
func parseSubscriptionMessage(t *testing.T, raw []json.RawMessage) (subid string, filters []Filter) { func parseSubscriptionMessage(t *testing.T, raw []json.RawMessage) (subid string, filters []Filter) {
t.Helper() t.Helper()
if len(raw) < 3 {
t.Fatalf("len(raw) = %d; want at least 3", len(raw)) assert.Greater(t, len(raw), 3)
}
var typ string var typ string
json.Unmarshal(raw[0], &typ) err := json.Unmarshal(raw[0], &typ)
if typ != "REQ" {
t.Errorf("typ = %q; want REQ", typ) assert.NoError(t, err)
} assert.Equal(t, "REQ", typ)
var id string var id string
if err := json.Unmarshal(raw[1], &id); err != nil { err = json.Unmarshal(raw[1], &id)
t.Errorf("json.Unmarshal sub id: %v", err) assert.NoError(t, err)
}
var ff []Filter var ff []Filter
for i, b := range raw[2:] { for _, b := range raw[2:] {
var f Filter var f Filter
if err := json.Unmarshal(b, &f); err != nil { err := json.Unmarshal(b, &f)
t.Errorf("json.Unmarshal filter %d: %v", i, err) assert.NoError(t, err)
}
ff = append(ff, f) ff = append(ff, f)
} }
return id, ff return id, ff

View File

@ -6,20 +6,19 @@ import (
"sync/atomic" "sync/atomic"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
) )
const RELAY = "wss://nos.lol" const RELAY = "wss://nos.lol"
// test if we can fetch a couple of random events // test if we can fetch a couple of random events
func TestSubscribeBasic(t *testing.T) { func TestSubscribeBasic(t *testing.T) {
rl := mustRelayConnect(RELAY) rl := mustRelayConnect(t, RELAY)
defer rl.Close() defer rl.Close()
sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindTextNote}, Limit: 2}}) sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindTextNote}, Limit: 2}})
if err != nil { assert.NoError(t, err)
t.Fatalf("subscription failed: %v", err)
return
}
timeout := time.After(5 * time.Second) timeout := time.After(5 * time.Second)
n := 0 n := 0
@ -27,9 +26,7 @@ func TestSubscribeBasic(t *testing.T) {
for { for {
select { select {
case event := <-sub.Events: case event := <-sub.Events:
if event == nil { assert.NotNil(t, event)
t.Fatalf("event is nil: %v", event)
}
n++ n++
case <-sub.EndOfStoredEvents: case <-sub.EndOfStoredEvents:
goto end goto end
@ -43,34 +40,26 @@ func TestSubscribeBasic(t *testing.T) {
} }
end: end:
if n != 2 { assert.Equal(t, 2, n)
t.Fatalf("expected 2 events, got %d", n)
}
} }
// test if we can do multiple nested subscriptions // test if we can do multiple nested subscriptions
func TestNestedSubscriptions(t *testing.T) { func TestNestedSubscriptions(t *testing.T) {
rl := mustRelayConnect(RELAY) rl := mustRelayConnect(t, RELAY)
defer rl.Close() defer rl.Close()
n := atomic.Uint32{} n := atomic.Uint32{}
// fetch 2 replies to a note // fetch 2 replies to a note
sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindTextNote}, Tags: TagMap{"e": []string{"0e34a74f8547e3b95d52a2543719b109fd0312aba144e2ef95cba043f42fe8c5"}}, Limit: 3}}) sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindTextNote}, Tags: TagMap{"e": []string{"0e34a74f8547e3b95d52a2543719b109fd0312aba144e2ef95cba043f42fe8c5"}}, Limit: 3}})
if err != nil { assert.NoError(t, err)
t.Fatalf("subscription 1 failed: %v", err)
return
}
for { for {
select { select {
case event := <-sub.Events: case event := <-sub.Events:
// now fetch author of this // now fetch author of this
sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindProfileMetadata}, Authors: []string{event.PubKey}, Limit: 1}}) sub, err := rl.Subscribe(context.Background(), Filters{{Kinds: []int{KindProfileMetadata}, Authors: []string{event.PubKey}, Limit: 1}})
if err != nil { assert.NoError(t, err)
t.Fatalf("subscription 2 failed: %v", err)
return
}
for { for {
select { select {

View File

@ -2,6 +2,8 @@ package nostr
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestTagHelpers(t *testing.T) { func TestTagHelpers(t *testing.T) {
@ -13,36 +15,14 @@ func TestTagHelpers(t *testing.T) {
Tag{"e", "ffffff"}, Tag{"e", "ffffff"},
} }
if tags.GetFirst([]string{"x"}) == nil { assert.NotNil(t, tags.GetFirst([]string{"x"}), "failed to get existing prefix")
t.Error("failed to get existing prefix") assert.Nil(t, tags.GetFirst([]string{"x", ""}), "got with wrong prefix")
} assert.NotNil(t, tags.GetFirst([]string{"p", "abcdef", "wss://"}), "failed to get with existing prefix")
if tags.GetFirst([]string{"x", ""}) != nil { assert.NotNil(t, tags.GetFirst([]string{"p", "abcdef", ""}), "failed to get with existing prefix (blank last string)")
t.Error("got with wrong prefix") assert.Equal(t, "ffffff", (*(tags.GetLast([]string{"e"})))[1], "failed to get last")
} assert.Equal(t, 2, len(tags.GetAll([]string{"e", ""})), "failed to get all")
if tags.GetFirst([]string{"p", "abcdef", "wss://"}) == nil { assert.Equal(t, 5, len(tags.AppendUnique(Tag{"e", "ffffff"})), "append unique changed the array size when existed")
t.Error("failed to get with existing prefix") assert.Equal(t, 6, len(tags.AppendUnique(Tag{"e", "bbbbbb"})), "append unique failed to append when didn't exist")
} assert.Equal(t, "ffffff", tags.AppendUnique(Tag{"e", "eeeeee"})[4][1], "append unique changed the order")
if tags.GetFirst([]string{"p", "abcdef", ""}) == nil { assert.Equal(t, "eeeeee", tags.AppendUnique(Tag{"e", "eeeeee"})[3][1], "append unique changed the order")
t.Error("failed to get with existing prefix (blank last string)")
}
if (*(tags.GetLast([]string{"e"})))[1] != "ffffff" {
t.Error("failed to get last")
}
if len(tags.GetAll([]string{"e", ""})) != 2 {
t.Error("failed to get all")
}
if len(tags.AppendUnique(Tag{"e", "ffffff"})) != 5 {
t.Error("append unique changed the array size when existed")
}
if len(tags.AppendUnique(Tag{"e", "bbbbbb"})) != 6 {
t.Error("append unique failed to append when didn't exist")
}
if tags.AppendUnique(Tag{"e", "eeeeee"})[4][1] != "ffffff" {
t.Error("append unique changed the order")
}
if tags.AppendUnique(Tag{"e", "eeeeee"})[3][1] != "eeeeee" {
t.Error("append unique changed the order")
}
} }

View File

@ -2,6 +2,8 @@ package nostr
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestIsValidRelayURL(t *testing.T) { func TestIsValidRelayURL(t *testing.T) {
@ -15,14 +17,10 @@ func TestIsValidRelayURL(t *testing.T) {
{"wss://relay.nostr.com", true}, {"wss://relay.nostr.com", true},
{"http://127.0.0.1", false}, {"http://127.0.0.1", false},
{"127.0.0.1", false}, {"127.0.0.1", false},
//{"wss://relay.nostr.com'", false},
//{"wss://relay.nostr.com'hiphop", true},
} }
for _, test := range tests { for _, test := range tests {
got := IsValidRelayURL(test.u) got := IsValidRelayURL(test.u)
if got != test.want { assert.Equal(t, test.want, got)
t.Errorf("IsValidRelayURL want %v for %q but got %v", test.want, test.u, got)
}
} }
} }