...

Source file src/golang.org/x/net/internal/quic/qlog/json_writer_test.go

Documentation: golang.org/x/net/internal/quic/qlog

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package qlog
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  	"fmt"
    13  	"log/slog"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  type testJSONOut struct {
    21  	bytes.Buffer
    22  }
    23  
    24  func (o *testJSONOut) Close() error { return nil }
    25  
    26  func newTestJSONWriter() *jsonWriter {
    27  	return &jsonWriter{w: &testJSONOut{}}
    28  }
    29  
    30  func wantJSONRecord(t *testing.T, w *jsonWriter, want string) {
    31  	t.Helper()
    32  	want = "\x1e" + want + "\n"
    33  	got := w.w.(*testJSONOut).String()
    34  	if got != want {
    35  		t.Errorf("jsonWriter contains unexpected output\ngot:  %q\nwant: %q", got, want)
    36  	}
    37  }
    38  
    39  func TestJSONWriterWriteConcurrentRecords(t *testing.T) {
    40  	w := newTestJSONWriter()
    41  	var wg sync.WaitGroup
    42  	for i := 0; i < 3; i++ {
    43  		wg.Add(1)
    44  		go func() {
    45  			defer wg.Done()
    46  			w.writeRecordStart()
    47  			w.writeInt64Field("field", 0)
    48  			w.writeRecordEnd()
    49  		}()
    50  	}
    51  	wg.Wait()
    52  	wantJSONRecord(t, w, strings.Join([]string{
    53  		`{"field":0}`,
    54  		`{"field":0}`,
    55  		`{"field":0}`,
    56  	}, "\n\x1e"))
    57  }
    58  
    59  func TestJSONWriterAttrs(t *testing.T) {
    60  	w := newTestJSONWriter()
    61  	w.writeRecordStart()
    62  	w.writeAttrsField("field", []slog.Attr{
    63  		slog.Any("any", errors.New("value")),
    64  		slog.Bool("bool", true),
    65  		slog.Duration("duration", 1*time.Second),
    66  		slog.Float64("float64", 1),
    67  		slog.Int64("int64", 1),
    68  		slog.String("string", "value"),
    69  		slog.Time("time", time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)),
    70  		slog.Uint64("uint64", 1),
    71  		slog.Group("group", "a", 1),
    72  	})
    73  	w.writeRecordEnd()
    74  	wantJSONRecord(t, w,
    75  		`{"field":{`+
    76  			`"any":"value",`+
    77  			`"bool":true,`+
    78  			`"duration":1000.000000,`+
    79  			`"float64":1,`+
    80  			`"int64":1,`+
    81  			`"string":"value",`+
    82  			`"time":946684800000.000000,`+
    83  			`"uint64":1,`+
    84  			`"group":{"a":1}`+
    85  			`}}`)
    86  }
    87  
    88  func TestJSONWriterObjectEmpty(t *testing.T) {
    89  	w := newTestJSONWriter()
    90  	w.writeRecordStart()
    91  	w.writeObjectField("field", func() {})
    92  	w.writeRecordEnd()
    93  	wantJSONRecord(t, w, `{"field":{}}`)
    94  }
    95  
    96  func TestJSONWriterObjectFields(t *testing.T) {
    97  	w := newTestJSONWriter()
    98  	w.writeRecordStart()
    99  	w.writeObjectField("field", func() {
   100  		w.writeStringField("a", "value")
   101  		w.writeInt64Field("b", 10)
   102  	})
   103  	w.writeRecordEnd()
   104  	wantJSONRecord(t, w, `{"field":{"a":"value","b":10}}`)
   105  }
   106  
   107  func TestJSONWriterRawField(t *testing.T) {
   108  	w := newTestJSONWriter()
   109  	w.writeRecordStart()
   110  	w.writeRawField("field", `[1]`)
   111  	w.writeRecordEnd()
   112  	wantJSONRecord(t, w, `{"field":[1]}`)
   113  }
   114  
   115  func TestJSONWriterBoolField(t *testing.T) {
   116  	w := newTestJSONWriter()
   117  	w.writeRecordStart()
   118  	w.writeBoolField("true", true)
   119  	w.writeBoolField("false", false)
   120  	w.writeRecordEnd()
   121  	wantJSONRecord(t, w, `{"true":true,"false":false}`)
   122  }
   123  
   124  func TestJSONWriterDurationField(t *testing.T) {
   125  	w := newTestJSONWriter()
   126  	w.writeRecordStart()
   127  	w.writeDurationField("field1", (10*time.Millisecond)+(2*time.Nanosecond))
   128  	w.writeDurationField("field2", -((10 * time.Millisecond) + (2 * time.Nanosecond)))
   129  	w.writeRecordEnd()
   130  	wantJSONRecord(t, w, `{"field1":10.000002,"field2":-10.000002}`)
   131  }
   132  
   133  func TestJSONWriterFloat64Field(t *testing.T) {
   134  	w := newTestJSONWriter()
   135  	w.writeRecordStart()
   136  	w.writeFloat64Field("field", 1.1)
   137  	w.writeRecordEnd()
   138  	wantJSONRecord(t, w, `{"field":1.1}`)
   139  }
   140  
   141  func TestJSONWriterInt64Field(t *testing.T) {
   142  	w := newTestJSONWriter()
   143  	w.writeRecordStart()
   144  	w.writeInt64Field("field", 1234)
   145  	w.writeRecordEnd()
   146  	wantJSONRecord(t, w, `{"field":1234}`)
   147  }
   148  
   149  func TestJSONWriterUint64Field(t *testing.T) {
   150  	w := newTestJSONWriter()
   151  	w.writeRecordStart()
   152  	w.writeUint64Field("field", 1234)
   153  	w.writeRecordEnd()
   154  	wantJSONRecord(t, w, `{"field":1234}`)
   155  }
   156  
   157  func TestJSONWriterStringField(t *testing.T) {
   158  	w := newTestJSONWriter()
   159  	w.writeRecordStart()
   160  	w.writeStringField("field", "value")
   161  	w.writeRecordEnd()
   162  	wantJSONRecord(t, w, `{"field":"value"}`)
   163  }
   164  
   165  func TestJSONWriterStringFieldEscaped(t *testing.T) {
   166  	w := newTestJSONWriter()
   167  	w.writeRecordStart()
   168  	w.writeStringField("field", "va\x00ue")
   169  	w.writeRecordEnd()
   170  	wantJSONRecord(t, w, `{"field":"va\u0000ue"}`)
   171  }
   172  
   173  func TestJSONWriterStringEscaping(t *testing.T) {
   174  	for c := 0; c <= 0xff; c++ {
   175  		w := newTestJSONWriter()
   176  		w.writeRecordStart()
   177  		w.writeStringField("field", string([]byte{byte(c)}))
   178  		w.writeRecordEnd()
   179  		var want string
   180  		if (c >= 0x20 && c <= 0x21) || (c >= 0x23 && c <= 0x5b) || (c >= 0x5d && c <= 0x7e) {
   181  			want = fmt.Sprintf(`%c`, c)
   182  		} else {
   183  			want = fmt.Sprintf(`\u%04x`, c)
   184  		}
   185  		wantJSONRecord(t, w, `{"field":"`+want+`"}`)
   186  	}
   187  }
   188  

View as plain text