blob: f657eb4a1c5c95cdd957c25cf6fa19b6c2e09314 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bigquery
import (
"testing"
"time"
"cloud.google.com/go/internal/testutil"
)
func TestParseInterval(t *testing.T) {
testcases := []struct {
inputStr string
wantInterval *IntervalValue
wantErr bool
}{
{
inputStr: "",
wantErr: true,
},
{
inputStr: "1-2 3",
wantErr: true,
},
{
inputStr: "1-2 3 4:5:6",
wantInterval: &IntervalValue{Years: 1, Months: 2, Days: 3, Hours: 4, Minutes: 5, Seconds: 6, SubSecondNanos: 0},
},
{
inputStr: "1-2 3 4:5:6.5",
wantInterval: &IntervalValue{Years: 1, Months: 2, Days: 3, Hours: 4, Minutes: 5, Seconds: 6, SubSecondNanos: 500000000},
},
{
inputStr: "-1-2 3 -4:5:6.123",
wantInterval: &IntervalValue{Years: -1, Months: -2, Days: 3, Hours: -4, Minutes: -5, Seconds: -6, SubSecondNanos: -123000000},
},
{
inputStr: "0-0 0 1:1:1.000000001",
wantInterval: &IntervalValue{Hours: 1, Minutes: 1, Seconds: 1, SubSecondNanos: 1},
},
}
for _, tc := range testcases {
gotInterval, err := ParseInterval(tc.inputStr)
if tc.wantErr {
if err != nil {
continue
}
t.Errorf("input %s: wanted err, got success", tc.inputStr)
}
if err != nil {
t.Errorf("input %s got err: %v", tc.inputStr, err)
}
if diff := testutil.Diff(gotInterval, tc.wantInterval); diff != "" {
t.Errorf("input %s: got=-, want=+:\n%s", tc.inputStr, diff)
}
}
}
func TestCanonicalInterval(t *testing.T) {
testcases := []struct {
description string
input *IntervalValue
wantCanonical *IntervalValue
wantString string
}{
{
description: "already canonical",
input: &IntervalValue{Years: 1, Months: 2, Days: 3, Hours: 4, Minutes: 5, Seconds: 6, SubSecondNanos: 0},
wantCanonical: &IntervalValue{Years: 1, Months: 2, Days: 3, Hours: 4, Minutes: 5, Seconds: 6, SubSecondNanos: 0},
wantString: "1-2 3 4:5:6",
},
{
description: "mixed Y-M",
input: &IntervalValue{Years: -1, Months: 28},
wantCanonical: &IntervalValue{Years: 1, Months: 4, Days: 0, Hours: 0, Minutes: 0, Seconds: 0, SubSecondNanos: 0},
wantString: "1-4 0 0:0:0",
},
{
description: "mixed Y-M",
input: &IntervalValue{Years: -1, Months: 28},
wantCanonical: &IntervalValue{Years: 1, Months: 4, Days: 0, Hours: 0, Minutes: 0, Seconds: 0, SubSecondNanos: 0},
wantString: "1-4 0 0:0:0",
},
{
description: "big month Y-M",
input: &IntervalValue{Years: 0, Months: -13},
wantCanonical: &IntervalValue{Years: -1, Months: -1, Days: 0, Hours: 0, Minutes: 0, Seconds: 0, SubSecondNanos: 0},
wantString: "-1-1 0 0:0:0",
},
{
description: "big days not normalized",
input: &IntervalValue{Days: 1000},
wantCanonical: &IntervalValue{Years: 0, Months: 0, Days: 1000, Hours: 0, Minutes: 0, Seconds: 0, SubSecondNanos: 0},
wantString: "0-0 1000 0:0:0",
},
{
description: "time reduced",
input: &IntervalValue{Minutes: 181, Seconds: 61, SubSecondNanos: 5},
wantCanonical: &IntervalValue{Hours: 3, Minutes: 2, Seconds: 1, SubSecondNanos: 5},
wantString: "0-0 0 3:2:1.000000005",
},
{
description: "subseconds oversized",
input: &IntervalValue{SubSecondNanos: 1900000000},
wantCanonical: &IntervalValue{Years: 0, Months: 0, Days: 0, Hours: 0, Minutes: 0, Seconds: 1, SubSecondNanos: 900000000},
wantString: "0-0 0 0:0:1.9",
},
}
for _, tc := range testcases {
gotCanonical := tc.input.Canonicalize()
if diff := testutil.Diff(gotCanonical, tc.wantCanonical); diff != "" {
t.Errorf("%s: got=-, want=+:\n%s", tc.description, diff)
}
gotStr := tc.input.String()
if gotStr != tc.wantString {
t.Errorf("%s mismatched strings. got %s want %s", tc.description, gotStr, tc.wantString)
}
}
}
func TestIntervalDuration(t *testing.T) {
testcases := []struct {
description string
inputInterval *IntervalValue
wantDuration time.Duration
wantInterval *IntervalValue
}{
{
description: "hour",
inputInterval: &IntervalValue{Hours: 1},
wantDuration: time.Duration(time.Hour),
wantInterval: &IntervalValue{Hours: 1},
},
{
description: "minute oversized",
inputInterval: &IntervalValue{Minutes: 62},
wantDuration: time.Duration(62 * time.Minute),
wantInterval: &IntervalValue{Hours: 1, Minutes: 2},
},
{
description: "other parts",
inputInterval: &IntervalValue{Months: 1, Days: 2},
wantDuration: time.Duration(32 * 24 * time.Hour),
wantInterval: &IntervalValue{Hours: 32 * 24},
},
}
for _, tc := range testcases {
gotDuration := tc.inputInterval.ToDuration()
// interval -> duration
if gotDuration != tc.wantDuration {
t.Errorf("%s: mismatched duration, got %v want %v", tc.description, gotDuration, tc.wantDuration)
}
// duration -> interval (canonical)
gotInterval := IntervalValueFromDuration(gotDuration)
if diff := testutil.Diff(gotInterval, tc.wantInterval); diff != "" {
t.Errorf("%s: got=-, want=+:\n%s", tc.description, diff)
}
}
}