|
| 1 | +// Copyright (c) HashiCorp, Inc. |
| 2 | +// SPDX-License-Identifier: MPL-2.0 |
| 3 | +package bigtable_test |
| 4 | + |
| 5 | +import ( |
| 6 | + "math" |
| 7 | + "math/rand" |
| 8 | + "strings" |
| 9 | + "testing" |
| 10 | + "time" |
| 11 | + |
| 12 | + "github.com/hashicorp/terraform-provider-google/google/services/bigtable" |
| 13 | +) |
| 14 | + |
| 15 | +var parseDurationTests = []struct { |
| 16 | + in string |
| 17 | + want time.Duration |
| 18 | +}{ |
| 19 | + // simple |
| 20 | + {"0", 0}, |
| 21 | + {"5s", 5 * time.Second}, |
| 22 | + {"30s", 30 * time.Second}, |
| 23 | + {"1478s", 1478 * time.Second}, |
| 24 | + // sign |
| 25 | + {"-5s", -5 * time.Second}, |
| 26 | + {"+5s", 5 * time.Second}, |
| 27 | + {"-0", 0}, |
| 28 | + {"+0", 0}, |
| 29 | + // decimal |
| 30 | + {"5.0s", 5 * time.Second}, |
| 31 | + {"5.6s", 5*time.Second + 600*time.Millisecond}, |
| 32 | + {"5.s", 5 * time.Second}, |
| 33 | + {".5s", 500 * time.Millisecond}, |
| 34 | + {"1.0s", 1 * time.Second}, |
| 35 | + {"1.00s", 1 * time.Second}, |
| 36 | + {"1.004s", 1*time.Second + 4*time.Millisecond}, |
| 37 | + {"1.0040s", 1*time.Second + 4*time.Millisecond}, |
| 38 | + {"100.00100s", 100*time.Second + 1*time.Millisecond}, |
| 39 | + // different units |
| 40 | + {"10ns", 10 * time.Nanosecond}, |
| 41 | + {"11us", 11 * time.Microsecond}, |
| 42 | + {"12µs", 12 * time.Microsecond}, // U+00B5 |
| 43 | + {"12μs", 12 * time.Microsecond}, // U+03BC |
| 44 | + {"13ms", 13 * time.Millisecond}, |
| 45 | + {"14s", 14 * time.Second}, |
| 46 | + {"15m", 15 * time.Minute}, |
| 47 | + {"16h", 16 * time.Hour}, |
| 48 | + {"5d", 5 * 24 * time.Hour}, |
| 49 | + // composite durations |
| 50 | + {"3h30m", 3*time.Hour + 30*time.Minute}, |
| 51 | + {"10.5s4m", 4*time.Minute + 10*time.Second + 500*time.Millisecond}, |
| 52 | + {"-2m3.4s", -(2*time.Minute + 3*time.Second + 400*time.Millisecond)}, |
| 53 | + {"1h2m3s4ms5us6ns", 1*time.Hour + 2*time.Minute + 3*time.Second + 4*time.Millisecond + 5*time.Microsecond + 6*time.Nanosecond}, |
| 54 | + {"39h9m14.425s", 39*time.Hour + 9*time.Minute + 14*time.Second + 425*time.Millisecond}, |
| 55 | + // large value |
| 56 | + {"52763797000ns", 52763797000 * time.Nanosecond}, |
| 57 | + // more than 9 digits after decimal point, see https://golang.org/issue/6617 |
| 58 | + {"0.3333333333333333333h", 20 * time.Minute}, |
| 59 | + // 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64 |
| 60 | + {"9007199254740993ns", (1<<53 + 1) * time.Nanosecond}, |
| 61 | + // largest duration that can be represented by int64 in nanoseconds |
| 62 | + {"9223372036854775807ns", (1<<63 - 1) * time.Nanosecond}, |
| 63 | + {"9223372036854775.807us", (1<<63 - 1) * time.Nanosecond}, |
| 64 | + {"9223372036s854ms775us807ns", (1<<63 - 1) * time.Nanosecond}, |
| 65 | + {"-9223372036854775808ns", -1 << 63 * time.Nanosecond}, |
| 66 | + {"-9223372036854775.808us", -1 << 63 * time.Nanosecond}, |
| 67 | + {"-9223372036s854ms775us808ns", -1 << 63 * time.Nanosecond}, |
| 68 | + // largest negative value |
| 69 | + {"-9223372036854775808ns", -1 << 63 * time.Nanosecond}, |
| 70 | + // largest negative round trip value, see https://golang.org/issue/48629 |
| 71 | + {"-2562047h47m16.854775808s", -1 << 63 * time.Nanosecond}, |
| 72 | + // huge string; issue 15011. |
| 73 | + {"0.100000000000000000000h", 6 * time.Minute}, |
| 74 | + // This value tests the first overflow check in leadingFraction. |
| 75 | + {"0.830103483285477580700h", 49*time.Minute + 48*time.Second + 372539827*time.Nanosecond}, |
| 76 | +} |
| 77 | + |
| 78 | +func TestParseDuration(t *testing.T) { |
| 79 | + for _, tc := range parseDurationTests { |
| 80 | + d, err := bigtable.ParseDuration(tc.in) |
| 81 | + if err != nil || d != tc.want { |
| 82 | + t.Errorf("bigtable.ParseDuration(%q) = %v, %v, want %v, nil", tc.in, d, err, tc.want) |
| 83 | + } |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +var parseDurationErrorTests = []struct { |
| 88 | + in string |
| 89 | + expect string |
| 90 | +}{ |
| 91 | + // invalid |
| 92 | + {"", `""`}, |
| 93 | + {"3", `"3"`}, |
| 94 | + {"-", `"-"`}, |
| 95 | + {"s", `"s"`}, |
| 96 | + {".", `"."`}, |
| 97 | + {"-.", `"-."`}, |
| 98 | + {".s", `".s"`}, |
| 99 | + {"+.s", `"+.s"`}, |
| 100 | + {"\x85\x85", `"\x85\x85"`}, |
| 101 | + {"\xffff", `"\xffff"`}, |
| 102 | + {"hello \xffff world", `"hello \xffff world"`}, |
| 103 | + {"\uFFFD", `"\xef\xbf\xbd"`}, // utf8.RuneError |
| 104 | + {"\uFFFD hello \uFFFD world", `"\xef\xbf\xbd hello \xef\xbf\xbd world"`}, // utf8.RuneError |
| 105 | + // overflow |
| 106 | + {"9223372036854775810ns", `"9223372036854775810ns"`}, |
| 107 | + {"9223372036854775808ns", `"9223372036854775808ns"`}, |
| 108 | + {"-9223372036854775809ns", `"-9223372036854775809ns"`}, |
| 109 | + {"9223372036854776us", `"9223372036854776us"`}, |
| 110 | + {"3000000h", `"3000000h"`}, |
| 111 | + {"9223372036854775.808us", `"9223372036854775.808us"`}, |
| 112 | + {"9223372036854ms775us808ns", `"9223372036854ms775us808ns"`}, |
| 113 | +} |
| 114 | + |
| 115 | +func TestParseDurationErrors(t *testing.T) { |
| 116 | + for _, tc := range parseDurationErrorTests { |
| 117 | + _, err := bigtable.ParseDuration(tc.in) |
| 118 | + if err == nil { |
| 119 | + t.Errorf("bigtable.ParseDuration(%q) = _, nil, want _, non-nil", tc.in) |
| 120 | + } else if !strings.Contains(err.Error(), tc.expect) { |
| 121 | + t.Errorf("bigtable.ParseDuration(%q) = _, %q, error does not contain %q", tc.in, err, tc.expect) |
| 122 | + } |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +func TestParseDurationRoundTrip(t *testing.T) { |
| 127 | + // https://golang.org/issue/48629 |
| 128 | + max0 := time.Duration(math.MaxInt64) |
| 129 | + max1, err := bigtable.ParseDuration(max0.String()) |
| 130 | + if err != nil || max0 != max1 { |
| 131 | + t.Errorf("round-trip failed: %d => %q => %d, %v", max0, max0.String(), max1, err) |
| 132 | + } |
| 133 | + |
| 134 | + min0 := time.Duration(math.MinInt64) |
| 135 | + min1, err := bigtable.ParseDuration(min0.String()) |
| 136 | + if err != nil || min0 != min1 { |
| 137 | + t.Errorf("round-trip failed: %d => %q => %d, %v", min0, min0.String(), min1, err) |
| 138 | + } |
| 139 | + |
| 140 | + for i := 0; i < 100; i++ { |
| 141 | + // Resolutions finer than milliseconds will result in |
| 142 | + // imprecise round-trips. |
| 143 | + d0 := time.Duration(rand.Int31()) * time.Millisecond |
| 144 | + s := d0.String() |
| 145 | + d1, err := bigtable.ParseDuration(s) |
| 146 | + if err != nil || d0 != d1 { |
| 147 | + t.Errorf("round-trip failed: %d => %q => %d, %v", d0, s, d1, err) |
| 148 | + } |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +func BenchmarkParseDuration(b *testing.B) { |
| 153 | + for i := 0; i < b.N; i++ { |
| 154 | + bigtable.ParseDuration("9007199254.740993ms") |
| 155 | + bigtable.ParseDuration("9007199254740993ns") |
| 156 | + } |
| 157 | +} |
0 commit comments