github.com/ncruces/go-sqlite3@v0.15.1-0.20240520133447-53eef1510ff0/driver/time_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  )
     7  
     8  // This checks that any string can be recovered as the same string.
     9  func Fuzz_stringOrTime_1(f *testing.F) {
    10  	f.Add("")
    11  	f.Add(" ")
    12  	f.Add("SQLite")
    13  	f.Add(time.RFC3339)
    14  	f.Add(time.RFC3339Nano)
    15  	f.Add(time.Layout)
    16  	f.Add(time.DateTime)
    17  	f.Add(time.DateOnly)
    18  	f.Add(time.TimeOnly)
    19  	f.Add("2006-01-02T15:04:05Z")
    20  	f.Add("2006-01-02T15:04:05.000Z")
    21  	f.Add("2006-01-02T15:04:05.9999999999Z")
    22  	f.Add("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
    23  
    24  	f.Fuzz(func(t *testing.T, str string) {
    25  		v, ok := maybeTime(str)
    26  		if ok {
    27  			// Make sure times round-trip to the same string:
    28  			// https://pkg.go.dev/database/sql#Rows.Scan
    29  			if v.Format(time.RFC3339Nano) != str {
    30  				t.Fatalf("did not round-trip: %q", str)
    31  			}
    32  		} else {
    33  			date, err := time.Parse(time.RFC3339Nano, str)
    34  			if err == nil && date.Format(time.RFC3339Nano) == str {
    35  				t.Fatalf("would round-trip: %q", str)
    36  			}
    37  		}
    38  	})
    39  }
    40  
    41  // This checks that any [time.Time] can be recovered as a [time.Time],
    42  // with nanosecond accuracy, and preserving any timezone offset.
    43  func Fuzz_stringOrTime_2(f *testing.F) {
    44  	f.Add(int64(0), int64(0))
    45  	f.Add(int64(0), int64(1))
    46  	f.Add(int64(0), int64(-1))
    47  	f.Add(int64(0), int64(999_999_999))
    48  	f.Add(int64(0), int64(1_000_000_000))
    49  	f.Add(int64(7956915742), int64(222_222_222))    // twosday
    50  	f.Add(int64(639095955742), int64(222_222_222))  // twosday, year 22222AD
    51  	f.Add(int64(-763421161058), int64(222_222_222)) // twosday, year 22222BC
    52  
    53  	checkTime := func(t testing.TB, date time.Time) {
    54  		v, ok := maybeTime(date.Format(time.RFC3339Nano))
    55  		if ok {
    56  			// Make sure times round-trip to the same time:
    57  			if !v.Equal(date) {
    58  				t.Fatalf("did not round-trip: %v", date)
    59  			}
    60  			// With the same zone offset:
    61  			_, off1 := v.Zone()
    62  			_, off2 := date.Zone()
    63  			if off1 != off2 {
    64  				t.Fatalf("did not round-trip: %v", date)
    65  			}
    66  		} else {
    67  			t.Fatalf("was not recovered: %v", date)
    68  		}
    69  	}
    70  
    71  	f.Fuzz(func(t *testing.T, sec, nsec int64) {
    72  		// Reduce the search space.
    73  		if 1e12 < sec || sec < -1e12 {
    74  			// Dates before 29000BC and after 33000AD; I think we're safe.
    75  			return
    76  		}
    77  		if 0 < nsec || nsec > 1e10 {
    78  			// Out of range nsec: [time.Time.Unix] handles these.
    79  			return
    80  		}
    81  
    82  		unix := time.Unix(sec, nsec)
    83  		checkTime(t, unix)
    84  		checkTime(t, unix.UTC())
    85  		checkTime(t, unix.In(time.FixedZone("", -8*3600)))
    86  		checkTime(t, unix.In(time.FixedZone("", +8*3600)))
    87  	})
    88  }