1// Copyright 2020 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 5package durationpb_test 6 7import ( 8 "math" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/google/go-cmp/cmp/cmpopts" 15 "google.golang.org/protobuf/internal/detrand" 16 "google.golang.org/protobuf/testing/protocmp" 17 18 durpb "google.golang.org/protobuf/types/known/durationpb" 19) 20 21func init() { 22 detrand.Disable() 23} 24 25const ( 26 minGoSeconds = math.MinInt64 / int64(1e9) 27 maxGoSeconds = math.MaxInt64 / int64(1e9) 28 absSeconds = 315576000000 // 10000yr * 365.25day/yr * 24hr/day * 60min/hr * 60sec/min 29) 30 31func TestToDuration(t *testing.T) { 32 tests := []struct { 33 in time.Duration 34 want *durpb.Duration 35 }{ 36 {in: time.Duration(0), want: &durpb.Duration{Seconds: 0, Nanos: 0}}, 37 {in: -time.Second, want: &durpb.Duration{Seconds: -1, Nanos: 0}}, 38 {in: +time.Second, want: &durpb.Duration{Seconds: +1, Nanos: 0}}, 39 {in: -time.Second - time.Millisecond, want: &durpb.Duration{Seconds: -1, Nanos: -1e6}}, 40 {in: +time.Second + time.Millisecond, want: &durpb.Duration{Seconds: +1, Nanos: +1e6}}, 41 {in: time.Duration(math.MinInt64), want: &durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}}, 42 {in: time.Duration(math.MaxInt64), want: &durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}}, 43 } 44 45 for _, tt := range tests { 46 got := durpb.New(tt.in) 47 if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" { 48 t.Errorf("New(%v) mismatch (-want +got):\n%s", tt.in, diff) 49 } 50 } 51} 52 53func TestFromDuration(t *testing.T) { 54 tests := []struct { 55 in *durpb.Duration 56 wantDur time.Duration 57 wantErr error 58 }{ 59 {in: nil, wantDur: time.Duration(0), wantErr: textError("invalid nil Duration")}, 60 {in: new(durpb.Duration), wantDur: time.Duration(0)}, 61 {in: &durpb.Duration{Seconds: -1, Nanos: 0}, wantDur: -time.Second}, 62 {in: &durpb.Duration{Seconds: +1, Nanos: 0}, wantDur: +time.Second}, 63 {in: &durpb.Duration{Seconds: 0, Nanos: -1}, wantDur: -time.Nanosecond}, 64 {in: &durpb.Duration{Seconds: 0, Nanos: +1}, wantDur: +time.Nanosecond}, 65 {in: &durpb.Duration{Seconds: -100, Nanos: 0}, wantDur: -100 * time.Second}, 66 {in: &durpb.Duration{Seconds: +100, Nanos: 0}, wantDur: +100 * time.Second}, 67 {in: &durpb.Duration{Seconds: -100, Nanos: -987}, wantDur: -100*time.Second - 987*time.Nanosecond}, 68 {in: &durpb.Duration{Seconds: +100, Nanos: +987}, wantDur: +100*time.Second + 987*time.Nanosecond}, 69 {in: &durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, wantDur: time.Duration(math.MinInt64)}, 70 {in: &durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, wantDur: time.Duration(math.MaxInt64)}, 71 {in: &durpb.Duration{Seconds: minGoSeconds - 1, Nanos: int32(math.MinInt64 - 1e9*minGoSeconds)}, wantDur: time.Duration(math.MinInt64)}, 72 {in: &durpb.Duration{Seconds: maxGoSeconds + 1, Nanos: int32(math.MaxInt64 - 1e9*maxGoSeconds)}, wantDur: time.Duration(math.MaxInt64)}, 73 {in: &durpb.Duration{Seconds: minGoSeconds, Nanos: int32(math.MinInt64-1e9*minGoSeconds) - 1}, wantDur: time.Duration(math.MinInt64)}, 74 {in: &durpb.Duration{Seconds: maxGoSeconds, Nanos: int32(math.MaxInt64-1e9*maxGoSeconds) + 1}, wantDur: time.Duration(math.MaxInt64)}, 75 {in: &durpb.Duration{Seconds: -123, Nanos: +456}, wantDur: -123*time.Second + 456*time.Nanosecond, wantErr: textError("duration (seconds:-123 nanos:456) has seconds and nanos with different signs")}, 76 {in: &durpb.Duration{Seconds: +123, Nanos: -456}, wantDur: +123*time.Second - 456*time.Nanosecond, wantErr: textError("duration (seconds:123 nanos:-456) has seconds and nanos with different signs")}, 77 {in: &durpb.Duration{Seconds: math.MinInt64}, wantDur: time.Duration(math.MinInt64), wantErr: textError("duration (seconds:-9223372036854775808) exceeds -10000 years")}, 78 {in: &durpb.Duration{Seconds: math.MaxInt64}, wantDur: time.Duration(math.MaxInt64), wantErr: textError("duration (seconds:9223372036854775807) exceeds +10000 years")}, 79 {in: &durpb.Duration{Seconds: -absSeconds, Nanos: -(1e9 - 1)}, wantDur: time.Duration(math.MinInt64)}, 80 {in: &durpb.Duration{Seconds: +absSeconds, Nanos: +(1e9 - 1)}, wantDur: time.Duration(math.MaxInt64)}, 81 {in: &durpb.Duration{Seconds: -absSeconds - 1, Nanos: 0}, wantDur: time.Duration(math.MinInt64), wantErr: textError("duration (seconds:-315576000001) exceeds -10000 years")}, 82 {in: &durpb.Duration{Seconds: +absSeconds + 1, Nanos: 0}, wantDur: time.Duration(math.MaxInt64), wantErr: textError("duration (seconds:315576000001) exceeds +10000 years")}, 83 } 84 85 for _, tt := range tests { 86 gotDur := tt.in.AsDuration() 87 if diff := cmp.Diff(tt.wantDur, gotDur); diff != "" { 88 t.Errorf("AsDuration(%v) mismatch (-want +got):\n%s", tt.in, diff) 89 } 90 gotErr := tt.in.CheckValid() 91 if diff := cmp.Diff(tt.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" { 92 t.Errorf("CheckValid(%v) mismatch (-want +got):\n%s", tt.in, diff) 93 } 94 } 95} 96 97type textError string 98 99func (e textError) Error() string { return string(e) } 100func (e textError) Is(err error) bool { return err != nil && strings.Contains(err.Error(), e.Error()) } 101