benchmark_test.go raw
1 package event
2
3 import (
4 "bytes"
5 "testing"
6 "time"
7
8 "next.orly.dev/pkg/nostr/encoders/hex"
9 "next.orly.dev/pkg/nostr/encoders/kind"
10 "next.orly.dev/pkg/nostr/encoders/tag"
11 "next.orly.dev/pkg/nostr/interfaces/signer/p8k"
12 "lukechampine.com/frand"
13 )
14
15 // createTestEvent creates a realistic test event with proper signing
16 func createTestEvent() *E {
17 signer := p8k.MustNew()
18 if err := signer.Generate(); err != nil {
19 panic(err)
20 }
21
22 ev := New()
23 ev.Pubkey = signer.Pub()
24 ev.CreatedAt = time.Now().Unix()
25 ev.Kind = kind.TextNote.K
26
27 // Create realistic tags
28 ev.Tags = tag.NewS(
29 tag.NewFromBytesSlice([]byte("t"), []byte("hashtag")),
30 tag.NewFromBytesSlice([]byte("e"), hex.EncAppend(nil, frand.Bytes(32))),
31 tag.NewFromBytesSlice([]byte("p"), hex.EncAppend(nil, frand.Bytes(32))),
32 )
33
34 // Create realistic content
35 ev.Content = []byte(`This is a test event with some content that includes special characters like < > & and "quotes" and various other things that might need escaping.`)
36
37 // Sign the event
38 if err := ev.Sign(signer); err != nil {
39 panic(err)
40 }
41
42 return ev
43 }
44
45 // createLargeTestEvent creates a larger event with more tags and content
46 func createLargeTestEvent() *E {
47 signer := p8k.MustNew()
48 if err := signer.Generate(); err != nil {
49 panic(err)
50 }
51
52 ev := New()
53 ev.Pubkey = signer.Pub()
54 ev.CreatedAt = time.Now().Unix()
55 ev.Kind = kind.TextNote.K
56
57 // Create many tags
58 tags := tag.NewS()
59 for i := 0; i < 20; i++ {
60 tags.Append(
61 tag.NewFromBytesSlice(
62 []byte("t"),
63 []byte("hashtag"+string(rune('0'+i))),
64 ),
65 )
66 if i%3 == 0 {
67 tags.Append(
68 tag.NewFromBytesSlice(
69 []byte("e"),
70 hex.EncAppend(nil, frand.Bytes(32)),
71 ),
72 )
73 }
74 }
75 ev.Tags = tags
76
77 // Large content
78 content := make([]byte, 0, 4096)
79 for i := 0; i < 50; i++ {
80 content = append(
81 content,
82 []byte("This is a longer piece of content that simulates real-world event content. ")...,
83 )
84 if i%10 == 0 {
85 content = append(
86 content, []byte("With special chars: < > & \" ' ")...,
87 )
88 }
89 }
90 ev.Content = content
91
92 // Sign the event
93 if err := ev.Sign(signer); err != nil {
94 panic(err)
95 }
96
97 return ev
98 }
99
100 // BenchmarkJSONMarshal benchmarks the JSON marshaling
101 func BenchmarkJSONMarshal(b *testing.B) {
102 ev := createTestEvent()
103 defer ev.Free()
104
105 b.ResetTimer()
106 b.ReportAllocs()
107
108 for i := 0; i < b.N; i++ {
109 _ = ev.Marshal(nil)
110 }
111 }
112
113 // BenchmarkJSONMarshalLarge benchmarks JSON marshaling with large events
114 func BenchmarkJSONMarshalLarge(b *testing.B) {
115 ev := createLargeTestEvent()
116 defer ev.Free()
117
118 b.ResetTimer()
119 b.ReportAllocs()
120
121 for i := 0; i < b.N; i++ {
122 _ = ev.Marshal(nil)
123 }
124 }
125
126 // BenchmarkJSONUnmarshal benchmarks JSON unmarshaling
127 func BenchmarkJSONUnmarshal(b *testing.B) {
128 ev := createTestEvent()
129 jsonData := ev.Marshal(nil)
130 defer ev.Free()
131
132 b.ResetTimer()
133 b.ReportAllocs()
134
135 for i := 0; i < b.N; i++ {
136 ev2 := New()
137 _, err := ev2.Unmarshal(jsonData)
138 if err != nil {
139 b.Fatal(err)
140 }
141 ev2.Free()
142 }
143 }
144
145 // BenchmarkBinaryMarshal benchmarks binary marshaling
146 func BenchmarkBinaryMarshal(b *testing.B) {
147 ev := createTestEvent()
148 defer ev.Free()
149
150 buf := &bytes.Buffer{}
151 b.ResetTimer()
152 b.ReportAllocs()
153
154 for i := 0; i < b.N; i++ {
155 buf.Reset()
156 ev.MarshalBinary(buf)
157 }
158 }
159
160 // BenchmarkBinaryMarshalLarge benchmarks binary marshaling with large events
161 func BenchmarkBinaryMarshalLarge(b *testing.B) {
162 ev := createLargeTestEvent()
163 defer ev.Free()
164
165 buf := &bytes.Buffer{}
166 b.ResetTimer()
167 b.ReportAllocs()
168
169 for i := 0; i < b.N; i++ {
170 buf.Reset()
171 ev.MarshalBinary(buf)
172 }
173 }
174
175 // BenchmarkBinaryUnmarshal benchmarks binary unmarshaling
176 func BenchmarkBinaryUnmarshal(b *testing.B) {
177 ev := createTestEvent()
178 buf := &bytes.Buffer{}
179 ev.MarshalBinary(buf)
180 binaryData := buf.Bytes()
181 defer ev.Free()
182
183 b.ResetTimer()
184 b.ReportAllocs()
185
186 for i := 0; i < b.N; i++ {
187 ev2 := New()
188 reader := bytes.NewReader(binaryData)
189 if err := ev2.UnmarshalBinary(reader); err != nil {
190 b.Fatal(err)
191 }
192 ev2.Free()
193 }
194 }
195
196 // BenchmarkCanonical benchmarks canonical encoding
197 func BenchmarkCanonical(b *testing.B) {
198 ev := createTestEvent()
199 defer ev.Free()
200
201 b.ResetTimer()
202 b.ReportAllocs()
203
204 for i := 0; i < b.N; i++ {
205 _ = ev.ToCanonical(nil)
206 }
207 }
208
209 // BenchmarkCanonicalLarge benchmarks canonical encoding with large events
210 func BenchmarkCanonicalLarge(b *testing.B) {
211 ev := createLargeTestEvent()
212 defer ev.Free()
213
214 b.ResetTimer()
215 b.ReportAllocs()
216
217 for i := 0; i < b.N; i++ {
218 _ = ev.ToCanonical(nil)
219 }
220 }
221
222 // BenchmarkGetIDBytes benchmarks ID generation (canonical + hash)
223 func BenchmarkGetIDBytes(b *testing.B) {
224 ev := createTestEvent()
225 defer ev.Free()
226
227 b.ResetTimer()
228 b.ReportAllocs()
229
230 for i := 0; i < b.N; i++ {
231 _ = ev.GetIDBytes()
232 }
233 }
234
235 // BenchmarkRoundTripJSON benchmarks JSON marshal/unmarshal round trip
236 func BenchmarkRoundTripJSON(b *testing.B) {
237 ev := createTestEvent()
238 defer ev.Free()
239
240 b.ResetTimer()
241 b.ReportAllocs()
242
243 for i := 0; i < b.N; i++ {
244 jsonData := ev.Marshal(nil)
245 ev2 := New()
246 _, err := ev2.Unmarshal(jsonData)
247 if err != nil {
248 b.Fatal(err)
249 }
250 ev2.Free()
251 }
252 }
253
254 // BenchmarkRoundTripBinary benchmarks binary marshal/unmarshal round trip
255 func BenchmarkRoundTripBinary(b *testing.B) {
256 ev := createTestEvent()
257 defer ev.Free()
258
259 buf := &bytes.Buffer{}
260 b.ResetTimer()
261 b.ReportAllocs()
262
263 for i := 0; i < b.N; i++ {
264 buf.Reset()
265 ev.MarshalBinary(buf)
266
267 ev2 := New()
268 reader := bytes.NewReader(buf.Bytes())
269 if err := ev2.UnmarshalBinary(reader); err != nil {
270 b.Fatal(err)
271 }
272 ev2.Free()
273 }
274 }
275
276 // BenchmarkEstimateSize benchmarks size estimation
277 func BenchmarkEstimateSize(b *testing.B) {
278 ev := createTestEvent()
279 defer ev.Free()
280
281 b.ResetTimer()
282 b.ReportAllocs()
283
284 for i := 0; i < b.N; i++ {
285 _ = ev.EstimateSize()
286 }
287 }
288