Source file src/encoding/json/v2/arshal_time_test.go

     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 goexperiment.jsonv2
     6  
     7  package json
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"math"
    13  	"strconv"
    14  	"testing"
    15  	"time"
    16  
    17  	"encoding/json/internal/jsonwire"
    18  )
    19  
    20  func baseLabel(base uint64) string {
    21  	if log10 := math.Log10(float64(base)); log10 == float64(int64(log10)) {
    22  		return fmt.Sprintf("1e%d", int(log10))
    23  	}
    24  	return fmt.Sprint(base)
    25  }
    26  
    27  var formatDurationTestdata = []struct {
    28  	td          time.Duration
    29  	base10Sec   string
    30  	base10Milli string
    31  	base10Micro string
    32  	base10Nano  string
    33  	iso8601     string
    34  }{
    35  	{math.MaxInt64, "9223372036.854775807", "9223372036854.775807", "9223372036854775.807", "9223372036854775807", "PT2562047H47M16.854775807S"},
    36  	{123*time.Hour + 4*time.Minute + 56*time.Second, "443096", "443096000", "443096000000", "443096000000000", "PT123H4M56S"},
    37  	{time.Hour, "3600", "3600000", "3600000000", "3600000000000", "PT1H"},
    38  	{time.Minute, "60", "60000", "60000000", "60000000000", "PT1M"},
    39  	{1e12 + 1e12, "2000", "2000000", "2000000000", "2000000000000", "PT33M20S"},
    40  	{1e12 + 1e11, "1100", "1100000", "1100000000", "1100000000000", "PT18M20S"},
    41  	{1e12 + 1e10, "1010", "1010000", "1010000000", "1010000000000", "PT16M50S"},
    42  	{1e12 + 1e9, "1001", "1001000", "1001000000", "1001000000000", "PT16M41S"},
    43  	{1e12 + 1e8, "1000.1", "1000100", "1000100000", "1000100000000", "PT16M40.1S"},
    44  	{1e12 + 1e7, "1000.01", "1000010", "1000010000", "1000010000000", "PT16M40.01S"},
    45  	{1e12 + 1e6, "1000.001", "1000001", "1000001000", "1000001000000", "PT16M40.001S"},
    46  	{1e12 + 1e5, "1000.0001", "1000000.1", "1000000100", "1000000100000", "PT16M40.0001S"},
    47  	{1e12 + 1e4, "1000.00001", "1000000.01", "1000000010", "1000000010000", "PT16M40.00001S"},
    48  	{1e12 + 1e3, "1000.000001", "1000000.001", "1000000001", "1000000001000", "PT16M40.000001S"},
    49  	{1e12 + 1e2, "1000.0000001", "1000000.0001", "1000000000.1", "1000000000100", "PT16M40.0000001S"},
    50  	{1e12 + 1e1, "1000.00000001", "1000000.00001", "1000000000.01", "1000000000010", "PT16M40.00000001S"},
    51  	{1e12 + 1e0, "1000.000000001", "1000000.000001", "1000000000.001", "1000000000001", "PT16M40.000000001S"},
    52  	{+(1e9 + 1), "1.000000001", "1000.000001", "1000000.001", "1000000001", "PT1.000000001S"},
    53  	{+(1e9), "1", "1000", "1000000", "1000000000", "PT1S"},
    54  	{+(1e9 - 1), "0.999999999", "999.999999", "999999.999", "999999999", "PT0.999999999S"},
    55  	{+100000000, "0.1", "100", "100000", "100000000", "PT0.1S"},
    56  	{+120000000, "0.12", "120", "120000", "120000000", "PT0.12S"},
    57  	{+123000000, "0.123", "123", "123000", "123000000", "PT0.123S"},
    58  	{+123400000, "0.1234", "123.4", "123400", "123400000", "PT0.1234S"},
    59  	{+123450000, "0.12345", "123.45", "123450", "123450000", "PT0.12345S"},
    60  	{+123456000, "0.123456", "123.456", "123456", "123456000", "PT0.123456S"},
    61  	{+123456700, "0.1234567", "123.4567", "123456.7", "123456700", "PT0.1234567S"},
    62  	{+123456780, "0.12345678", "123.45678", "123456.78", "123456780", "PT0.12345678S"},
    63  	{+123456789, "0.123456789", "123.456789", "123456.789", "123456789", "PT0.123456789S"},
    64  	{+12345678, "0.012345678", "12.345678", "12345.678", "12345678", "PT0.012345678S"},
    65  	{+1234567, "0.001234567", "1.234567", "1234.567", "1234567", "PT0.001234567S"},
    66  	{+123456, "0.000123456", "0.123456", "123.456", "123456", "PT0.000123456S"},
    67  	{+12345, "0.000012345", "0.012345", "12.345", "12345", "PT0.000012345S"},
    68  	{+1234, "0.000001234", "0.001234", "1.234", "1234", "PT0.000001234S"},
    69  	{+123, "0.000000123", "0.000123", "0.123", "123", "PT0.000000123S"},
    70  	{+12, "0.000000012", "0.000012", "0.012", "12", "PT0.000000012S"},
    71  	{+1, "0.000000001", "0.000001", "0.001", "1", "PT0.000000001S"},
    72  	{0, "0", "0", "0", "0", "PT0S"},
    73  	{-1, "-0.000000001", "-0.000001", "-0.001", "-1", "-PT0.000000001S"},
    74  	{-12, "-0.000000012", "-0.000012", "-0.012", "-12", "-PT0.000000012S"},
    75  	{-123, "-0.000000123", "-0.000123", "-0.123", "-123", "-PT0.000000123S"},
    76  	{-1234, "-0.000001234", "-0.001234", "-1.234", "-1234", "-PT0.000001234S"},
    77  	{-12345, "-0.000012345", "-0.012345", "-12.345", "-12345", "-PT0.000012345S"},
    78  	{-123456, "-0.000123456", "-0.123456", "-123.456", "-123456", "-PT0.000123456S"},
    79  	{-1234567, "-0.001234567", "-1.234567", "-1234.567", "-1234567", "-PT0.001234567S"},
    80  	{-12345678, "-0.012345678", "-12.345678", "-12345.678", "-12345678", "-PT0.012345678S"},
    81  	{-123456789, "-0.123456789", "-123.456789", "-123456.789", "-123456789", "-PT0.123456789S"},
    82  	{-123456780, "-0.12345678", "-123.45678", "-123456.78", "-123456780", "-PT0.12345678S"},
    83  	{-123456700, "-0.1234567", "-123.4567", "-123456.7", "-123456700", "-PT0.1234567S"},
    84  	{-123456000, "-0.123456", "-123.456", "-123456", "-123456000", "-PT0.123456S"},
    85  	{-123450000, "-0.12345", "-123.45", "-123450", "-123450000", "-PT0.12345S"},
    86  	{-123400000, "-0.1234", "-123.4", "-123400", "-123400000", "-PT0.1234S"},
    87  	{-123000000, "-0.123", "-123", "-123000", "-123000000", "-PT0.123S"},
    88  	{-120000000, "-0.12", "-120", "-120000", "-120000000", "-PT0.12S"},
    89  	{-100000000, "-0.1", "-100", "-100000", "-100000000", "-PT0.1S"},
    90  	{-(1e9 - 1), "-0.999999999", "-999.999999", "-999999.999", "-999999999", "-PT0.999999999S"},
    91  	{-(1e9), "-1", "-1000", "-1000000", "-1000000000", "-PT1S"},
    92  	{-(1e9 + 1), "-1.000000001", "-1000.000001", "-1000000.001", "-1000000001", "-PT1.000000001S"},
    93  	{math.MinInt64, "-9223372036.854775808", "-9223372036854.775808", "-9223372036854775.808", "-9223372036854775808", "-PT2562047H47M16.854775808S"},
    94  }
    95  
    96  func TestFormatDuration(t *testing.T) {
    97  	var gotBuf []byte
    98  	check := func(td time.Duration, s string, base uint64) {
    99  		a := durationArshaler{td, base}
   100  		gotBuf, _ = a.appendMarshal(gotBuf[:0])
   101  		if string(gotBuf) != s {
   102  			t.Errorf("formatDuration(%d, %s) = %q, want %q", td, baseLabel(base), string(gotBuf), s)
   103  		}
   104  		if err := a.unmarshal(gotBuf); err != nil {
   105  			t.Errorf("parseDuration(%q, %s) error: %v", gotBuf, baseLabel(base), err)
   106  		}
   107  		if a.td != td {
   108  			t.Errorf("parseDuration(%q, %s) = %d, want %d", gotBuf, baseLabel(base), a.td, td)
   109  		}
   110  	}
   111  	for _, tt := range formatDurationTestdata {
   112  		check(tt.td, tt.base10Sec, 1e9)
   113  		check(tt.td, tt.base10Milli, 1e6)
   114  		check(tt.td, tt.base10Micro, 1e3)
   115  		check(tt.td, tt.base10Nano, 1e0)
   116  		check(tt.td, tt.iso8601, 8601)
   117  	}
   118  }
   119  
   120  var parseDurationTestdata = []struct {
   121  	in      string
   122  	base    uint64
   123  	want    time.Duration
   124  	wantErr error
   125  }{
   126  	{"0", 1e0, 0, nil},
   127  	{"0.", 1e0, 0, strconv.ErrSyntax},
   128  	{"0.0", 1e0, 0, nil},
   129  	{"0.00", 1e0, 0, nil},
   130  	{"00.0", 1e0, 0, strconv.ErrSyntax},
   131  	{"+0", 1e0, 0, strconv.ErrSyntax},
   132  	{"1e0", 1e0, 0, strconv.ErrSyntax},
   133  	{"1.000000000x", 1e9, 0, strconv.ErrSyntax},
   134  	{"1.000000x", 1e6, 0, strconv.ErrSyntax},
   135  	{"1.000x", 1e3, 0, strconv.ErrSyntax},
   136  	{"1.x", 1e0, 0, strconv.ErrSyntax},
   137  	{"1.0000000009", 1e9, +time.Second, nil},
   138  	{"1.0000009", 1e6, +time.Millisecond, nil},
   139  	{"1.0009", 1e3, +time.Microsecond, nil},
   140  	{"1.9", 1e0, +time.Nanosecond, nil},
   141  	{"-9223372036854775809", 1e0, 0, strconv.ErrRange},
   142  	{"9223372036854775.808", 1e3, 0, strconv.ErrRange},
   143  	{"-9223372036854.775809", 1e6, 0, strconv.ErrRange},
   144  	{"9223372036.854775808", 1e9, 0, strconv.ErrRange},
   145  	{"-1.9", 1e0, -time.Nanosecond, nil},
   146  	{"-1.0009", 1e3, -time.Microsecond, nil},
   147  	{"-1.0000009", 1e6, -time.Millisecond, nil},
   148  	{"-1.0000000009", 1e9, -time.Second, nil},
   149  	{"", 8601, 0, strconv.ErrSyntax},
   150  	{"P", 8601, 0, strconv.ErrSyntax},
   151  	{"PT", 8601, 0, strconv.ErrSyntax},
   152  	{"PT0", 8601, 0, strconv.ErrSyntax},
   153  	{"DT0S", 8601, 0, strconv.ErrSyntax},
   154  	{"PT0S", 8601, 0, nil},
   155  	{" PT0S", 8601, 0, strconv.ErrSyntax},
   156  	{"PT0S ", 8601, 0, strconv.ErrSyntax},
   157  	{"+PT0S", 8601, 0, nil},
   158  	{"PT0.M", 8601, 0, strconv.ErrSyntax},
   159  	{"PT0.S", 8601, 0, strconv.ErrSyntax},
   160  	{"PT0.0S", 8601, 0, nil},
   161  	{"PT0.0_0H", 8601, 0, strconv.ErrSyntax},
   162  	{"PT0.0_0M", 8601, 0, strconv.ErrSyntax},
   163  	{"PT0.0_0S", 8601, 0, strconv.ErrSyntax},
   164  	{"PT.0S", 8601, 0, strconv.ErrSyntax},
   165  	{"PT00.0S", 8601, 0, nil},
   166  	{"PT0S", 8601, 0, nil},
   167  	{"PT1,5S", 8601, time.Second + 500*time.Millisecond, nil},
   168  	{"PT1H", 8601, time.Hour, nil},
   169  	{"PT1H0S", 8601, time.Hour, nil},
   170  	{"PT0S", 8601, 0, nil},
   171  	{"PT00S", 8601, 0, nil},
   172  	{"PT000S", 8601, 0, nil},
   173  	{"PTS", 8601, 0, strconv.ErrSyntax},
   174  	{"PT1M", 8601, time.Minute, nil},
   175  	{"PT01M", 8601, time.Minute, nil},
   176  	{"PT001M", 8601, time.Minute, nil},
   177  	{"PT1H59S", 8601, time.Hour + 59*time.Second, nil},
   178  	{"PT123H4M56.789S", 8601, 123*time.Hour + 4*time.Minute + 56*time.Second + 789*time.Millisecond, nil},
   179  	{"-PT123H4M56.789S", 8601, -123*time.Hour - 4*time.Minute - 56*time.Second - 789*time.Millisecond, nil},
   180  	{"PT0H0S", 8601, 0, nil},
   181  	{"PT0H", 8601, 0, nil},
   182  	{"PT0M", 8601, 0, nil},
   183  	{"-PT0S", 8601, 0, nil},
   184  	{"PT1M0S", 8601, time.Minute, nil},
   185  	{"PT0H1M0S", 8601, time.Minute, nil},
   186  	{"PT01H02M03S", 8601, 1*time.Hour + 2*time.Minute + 3*time.Second, nil},
   187  	{"PT0,123S", 8601, 123 * time.Millisecond, nil},
   188  	{"PT1.S", 8601, 0, strconv.ErrSyntax},
   189  	{"PT1.000S", 8601, time.Second, nil},
   190  	{"PT0.025H", 8601, time.Minute + 30*time.Second, nil},
   191  	{"PT0.025H0M", 8601, 0, strconv.ErrSyntax},
   192  	{"PT1.5M", 8601, time.Minute + 30*time.Second, nil},
   193  	{"PT1.5M0S", 8601, 0, strconv.ErrSyntax},
   194  	{"PT60M", 8601, time.Hour, nil},
   195  	{"PT3600S", 8601, time.Hour, nil},
   196  	{"PT1H2M3.0S", 8601, 1*time.Hour + 2*time.Minute + 3*time.Second, nil},
   197  	{"pt1h2m3,0s", 8601, 1*time.Hour + 2*time.Minute + 3*time.Second, nil},
   198  	{"PT-1H-2M-3S", 8601, 0, strconv.ErrSyntax},
   199  	{"P1Y", 8601, time.Duration(daysPerYear * 24 * 60 * 60 * 1e9), errInaccurateDateUnits},
   200  	{"P1.0Y", 8601, 0, strconv.ErrSyntax},
   201  	{"P1M", 8601, time.Duration(daysPerYear / 12 * 24 * 60 * 60 * 1e9), errInaccurateDateUnits},
   202  	{"P1.0M", 8601, 0, strconv.ErrSyntax},
   203  	{"P1W", 8601, 7 * 24 * time.Hour, errInaccurateDateUnits},
   204  	{"P1.0W", 8601, 0, strconv.ErrSyntax},
   205  	{"P1D", 8601, 24 * time.Hour, errInaccurateDateUnits},
   206  	{"P1.0D", 8601, 0, strconv.ErrSyntax},
   207  	{"P1W1S", 8601, 0, strconv.ErrSyntax},
   208  	{"-P1Y2M3W4DT5H6M7.8S", 8601, -(time.Duration(14*daysPerYear/12*24*60*60*1e9) + time.Duration((3*7+4)*24*60*60*1e9) + 5*time.Hour + 6*time.Minute + 7*time.Second + 800*time.Millisecond), errInaccurateDateUnits},
   209  	{"-p1y2m3w4dt5h6m7.8s", 8601, -(time.Duration(14*daysPerYear/12*24*60*60*1e9) + time.Duration((3*7+4)*24*60*60*1e9) + 5*time.Hour + 6*time.Minute + 7*time.Second + 800*time.Millisecond), errInaccurateDateUnits},
   210  	{"P0Y0M0DT1H2M3S", 8601, 1*time.Hour + 2*time.Minute + 3*time.Second, errInaccurateDateUnits},
   211  	{"PT0.0000000001S", 8601, 0, nil},
   212  	{"PT0.0000000005S", 8601, 0, nil},
   213  	{"PT0.000000000500000000S", 8601, 0, nil},
   214  	{"PT0.000000000499999999S", 8601, 0, nil},
   215  	{"PT2562047H47M16.854775808S", 8601, 0, strconv.ErrRange},
   216  	{"-PT2562047H47M16.854775809S", 8601, 0, strconv.ErrRange},
   217  	{"PT9223372036.854775807S", 8601, math.MaxInt64, nil},
   218  	{"PT9223372036.854775808S", 8601, 0, strconv.ErrRange},
   219  	{"-PT9223372036.854775808S", 8601, math.MinInt64, nil},
   220  	{"-PT9223372036.854775809S", 8601, 0, strconv.ErrRange},
   221  	{"PT18446744073709551616S", 8601, 0, strconv.ErrRange},
   222  	{"PT5124096H", 8601, 0, strconv.ErrRange},
   223  	{"PT2562047.7880152155019444H", 8601, math.MaxInt64, nil},
   224  	{"PT2562047.7880152155022222H", 8601, 0, strconv.ErrRange},
   225  	{"PT5124094H94M33.709551616S", 8601, 0, strconv.ErrRange},
   226  }
   227  
   228  func TestParseDuration(t *testing.T) {
   229  	for _, tt := range parseDurationTestdata {
   230  		a := durationArshaler{base: tt.base}
   231  		switch err := a.unmarshal([]byte(tt.in)); {
   232  		case a.td != tt.want:
   233  			t.Errorf("parseDuration(%q, %s) = %v, want %v", tt.in, baseLabel(tt.base), a.td, tt.want)
   234  		case !errors.Is(err, tt.wantErr):
   235  			t.Errorf("parseDuration(%q, %s) error = %v, want %v", tt.in, baseLabel(tt.base), err, tt.wantErr)
   236  		}
   237  	}
   238  }
   239  
   240  func FuzzFormatDuration(f *testing.F) {
   241  	for _, tt := range formatDurationTestdata {
   242  		f.Add(int64(tt.td))
   243  	}
   244  	f.Fuzz(func(t *testing.T, want int64) {
   245  		var buf []byte
   246  		for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9, 8601} {
   247  			a := durationArshaler{td: time.Duration(want), base: base}
   248  			buf, _ = a.appendMarshal(buf[:0])
   249  			switch err := a.unmarshal(buf); {
   250  			case err != nil:
   251  				t.Fatalf("parseDuration(%q, %s) error: %v", buf, baseLabel(base), err)
   252  			case a.td != time.Duration(want):
   253  				t.Fatalf("parseDuration(%q, %s) = %v, want %v", buf, baseLabel(base), a.td, time.Duration(want))
   254  			}
   255  		}
   256  	})
   257  }
   258  
   259  func FuzzParseDuration(f *testing.F) {
   260  	for _, tt := range parseDurationTestdata {
   261  		f.Add([]byte(tt.in))
   262  	}
   263  	f.Fuzz(func(t *testing.T, in []byte) {
   264  		for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9, 8601} {
   265  			a := durationArshaler{base: base}
   266  			switch err := a.unmarshal(in); {
   267  			case err != nil: // nothing else to check
   268  			case base != 8601:
   269  				if n, err := jsonwire.ConsumeNumber(in); err != nil || n != len(in) {
   270  					t.Fatalf("parseDuration(%q) error is nil for invalid JSON number", in)
   271  				}
   272  			}
   273  		}
   274  	})
   275  }
   276  
   277  type formatTimeTestdataEntry struct {
   278  	ts        time.Time
   279  	unixSec   string
   280  	unixMilli string
   281  	unixMicro string
   282  	unixNano  string
   283  }
   284  
   285  var formatTimeTestdata = func() []formatTimeTestdataEntry {
   286  	out := []formatTimeTestdataEntry{
   287  		{time.Unix(math.MaxInt64/int64(1e0), 1e9-1).UTC(), "9223372036854775807.999999999", "9223372036854775807999.999999", "9223372036854775807999999.999", "9223372036854775807999999999"},
   288  		{time.Unix(math.MaxInt64/int64(1e1), 1e9-1).UTC(), "922337203685477580.999999999", "922337203685477580999.999999", "922337203685477580999999.999", "922337203685477580999999999"},
   289  		{time.Unix(math.MaxInt64/int64(1e2), 1e9-1).UTC(), "92233720368547758.999999999", "92233720368547758999.999999", "92233720368547758999999.999", "92233720368547758999999999"},
   290  		{time.Unix(math.MinInt64, 1).UTC(), "-9223372036854775807.999999999", "-9223372036854775807999.999999", "-9223372036854775807999999.999", "-9223372036854775807999999999"},
   291  		{time.Unix(math.MinInt64, 0).UTC(), "-9223372036854775808", "-9223372036854775808000", "-9223372036854775808000000", "-9223372036854775808000000000"},
   292  	}
   293  	for _, tt := range formatDurationTestdata {
   294  		out = append(out, formatTimeTestdataEntry{time.Unix(0, int64(tt.td)).UTC(), tt.base10Sec, tt.base10Milli, tt.base10Micro, tt.base10Nano})
   295  	}
   296  	return out
   297  }()
   298  
   299  func TestFormatTime(t *testing.T) {
   300  	var gotBuf []byte
   301  	check := func(ts time.Time, s string, pow10 uint64) {
   302  		gotBuf = appendTimeUnix(gotBuf[:0], ts, pow10)
   303  		if string(gotBuf) != s {
   304  			t.Errorf("formatTime(time.Unix(%d, %d), %s) = %q, want %q", ts.Unix(), ts.Nanosecond(), baseLabel(pow10), string(gotBuf), s)
   305  		}
   306  		gotTS, err := parseTimeUnix(gotBuf, pow10)
   307  		if err != nil {
   308  			t.Errorf("parseTime(%q, %s) error: %v", gotBuf, baseLabel(pow10), err)
   309  		}
   310  		if !gotTS.Equal(ts) {
   311  			t.Errorf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", gotBuf, baseLabel(pow10), gotTS.Unix(), gotTS.Nanosecond(), ts.Unix(), ts.Nanosecond())
   312  		}
   313  	}
   314  	for _, tt := range formatTimeTestdata {
   315  		check(tt.ts, tt.unixSec, 1e0)
   316  		check(tt.ts, tt.unixMilli, 1e3)
   317  		check(tt.ts, tt.unixMicro, 1e6)
   318  		check(tt.ts, tt.unixNano, 1e9)
   319  	}
   320  }
   321  
   322  var parseTimeTestdata = []struct {
   323  	in      string
   324  	base    uint64
   325  	want    time.Time
   326  	wantErr error
   327  }{
   328  	{"0", 1e0, time.Unix(0, 0).UTC(), nil},
   329  	{"0.", 1e0, time.Time{}, strconv.ErrSyntax},
   330  	{"0.0", 1e0, time.Unix(0, 0).UTC(), nil},
   331  	{"0.00", 1e0, time.Unix(0, 0).UTC(), nil},
   332  	{"00.0", 1e0, time.Time{}, strconv.ErrSyntax},
   333  	{"+0", 1e0, time.Time{}, strconv.ErrSyntax},
   334  	{"1e0", 1e0, time.Time{}, strconv.ErrSyntax},
   335  	{"1234567890123456789012345678901234567890", 1e0, time.Time{}, strconv.ErrRange},
   336  	{"9223372036854775808000.000000", 1e3, time.Time{}, strconv.ErrRange},
   337  	{"9223372036854775807999999.9999", 1e6, time.Unix(math.MaxInt64, 1e9-1).UTC(), nil},
   338  	{"9223372036854775807999999999.9", 1e9, time.Unix(math.MaxInt64, 1e9-1).UTC(), nil},
   339  	{"9223372036854775807.999999999x", 1e0, time.Time{}, strconv.ErrSyntax},
   340  	{"9223372036854775807000000000", 1e9, time.Unix(math.MaxInt64, 0).UTC(), nil},
   341  	{"-9223372036854775808", 1e0, time.Unix(math.MinInt64, 0).UTC(), nil},
   342  	{"-9223372036854775808000.000001", 1e3, time.Time{}, strconv.ErrRange},
   343  	{"-9223372036854775808000000.0001", 1e6, time.Unix(math.MinInt64, 0).UTC(), nil},
   344  	{"-9223372036854775808000000000.x", 1e9, time.Time{}, strconv.ErrSyntax},
   345  	{"-1234567890123456789012345678901234567890", 1e9, time.Time{}, strconv.ErrRange},
   346  }
   347  
   348  func TestParseTime(t *testing.T) {
   349  	for _, tt := range parseTimeTestdata {
   350  		a := timeArshaler{base: tt.base}
   351  		switch err := a.unmarshal([]byte(tt.in)); {
   352  		case a.tt != tt.want:
   353  			t.Errorf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", tt.in, baseLabel(tt.base), a.tt.Unix(), a.tt.Nanosecond(), tt.want.Unix(), tt.want.Nanosecond())
   354  		case !errors.Is(err, tt.wantErr):
   355  			t.Errorf("parseTime(%q, %s) error = %v, want %v", tt.in, baseLabel(tt.base), err, tt.wantErr)
   356  		}
   357  	}
   358  }
   359  
   360  func FuzzFormatTime(f *testing.F) {
   361  	for _, tt := range formatTimeTestdata {
   362  		f.Add(tt.ts.Unix(), int64(tt.ts.Nanosecond()))
   363  	}
   364  	f.Fuzz(func(t *testing.T, wantSec, wantNano int64) {
   365  		want := time.Unix(wantSec, int64(uint64(wantNano)%1e9)).UTC()
   366  		var buf []byte
   367  		for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9} {
   368  			a := timeArshaler{tt: want, base: base}
   369  			buf, _ = a.appendMarshal(buf[:0])
   370  			switch err := a.unmarshal(buf); {
   371  			case err != nil:
   372  				t.Fatalf("parseTime(%q, %s) error: %v", buf, baseLabel(base), err)
   373  			case a.tt != want:
   374  				t.Fatalf("parseTime(%q, %s) = time.Unix(%d, %d), want time.Unix(%d, %d)", buf, baseLabel(base), a.tt.Unix(), a.tt.Nanosecond(), want.Unix(), want.Nanosecond())
   375  			}
   376  		}
   377  	})
   378  }
   379  
   380  func FuzzParseTime(f *testing.F) {
   381  	for _, tt := range parseTimeTestdata {
   382  		f.Add([]byte(tt.in))
   383  	}
   384  	f.Fuzz(func(t *testing.T, in []byte) {
   385  		for _, base := range [...]uint64{1e0, 1e3, 1e6, 1e9} {
   386  			a := timeArshaler{base: base}
   387  			if err := a.unmarshal(in); err == nil {
   388  				if n, err := jsonwire.ConsumeNumber(in); err != nil || n != len(in) {
   389  					t.Fatalf("parseTime(%q) error is nil for invalid JSON number", in)
   390  				}
   391  			}
   392  		}
   393  	})
   394  }
   395  

View as plain text