github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/timeutil/pgdate/field_extract_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package pgdate 12 13 import ( 14 "reflect" 15 "testing" 16 "time" 17 18 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 19 ) 20 21 func TestExtractRelative(t *testing.T) { 22 tests := []struct { 23 s string 24 rel int 25 }{ 26 { 27 s: keywordYesterday, 28 rel: -1, 29 }, 30 { 31 s: keywordToday, 32 rel: 0, 33 }, 34 { 35 s: keywordTomorrow, 36 rel: 1, 37 }, 38 } 39 40 now := time.Date(2018, 10, 17, 0, 0, 0, 0, time.UTC) 41 for _, tc := range tests { 42 t.Run(tc.s, func(t *testing.T) { 43 d, err := ParseDate(now, ParseModeYMD, tc.s) 44 if err != nil { 45 t.Fatal(err) 46 } 47 ts, err := d.ToTime() 48 if err != nil { 49 t.Fatal(err) 50 } 51 exp := now.AddDate(0, 0, tc.rel) 52 if ts != exp { 53 t.Fatalf("expected %v, got %v", exp, ts) 54 } 55 }) 56 } 57 } 58 59 func TestExtractSentinels(t *testing.T) { 60 now := timeutil.Unix(42, 56) 61 tests := []struct { 62 s string 63 expected time.Time 64 err bool 65 }{ 66 { 67 s: keywordEpoch, 68 expected: TimeEpoch, 69 }, 70 { 71 s: keywordInfinity, 72 expected: TimeInfinity, 73 }, 74 { 75 s: "-" + keywordInfinity, 76 expected: TimeNegativeInfinity, 77 }, 78 { 79 s: keywordNow, 80 expected: now, 81 }, 82 { 83 s: keywordNow + " tomorrow", 84 err: true, 85 }, 86 } 87 for _, tc := range tests { 88 t.Run(tc.s, func(t *testing.T) { 89 fe := fieldExtract{now: now} 90 err := fe.Extract(tc.s) 91 if tc.err { 92 if err == nil { 93 t.Fatal("expected error") 94 } 95 return 96 } 97 if err != nil { 98 t.Fatal(err) 99 } 100 if fe.MakeTimestamp() != tc.expected { 101 t.Fatal("did not get expected sentinel value") 102 } 103 }) 104 } 105 } 106 107 func TestFieldExtractSet(t *testing.T) { 108 p := fieldExtract{wanted: dateFields} 109 if err := p.Set(fieldYear, 2018); err != nil { 110 t.Fatal(err) 111 } 112 if err := p.Set(fieldMonth, 1); err != nil { 113 t.Fatal(err) 114 } 115 if p.Wants(fieldSecond) { 116 t.Fatal("should not want RelativeDate") 117 } 118 t.Log(p.String()) 119 } 120 121 func TestChunking(t *testing.T) { 122 // Using an over-long UTF-8 sequence from: 123 // https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt 124 badString := string([]byte{0xe0, 0x80, 0xaf}) 125 126 tests := []struct { 127 s string 128 count int 129 expected []stringChunk 130 tail string 131 }{ 132 { 133 // Empty input. 134 s: "", 135 expected: []stringChunk{}, 136 }, 137 { 138 s: "@@ foo!bar baz %%", 139 count: 3, 140 expected: []stringChunk{ 141 {"@@ ", "foo"}, 142 {"!", "bar"}, 143 {" ", "baz"}, 144 }, 145 tail: " %%", 146 }, 147 { 148 s: "Εργαστήρια κατσαρίδων", /* Cockroach Labs */ 149 count: 2, 150 expected: []stringChunk{{"", "Εργαστήρια"}, {" ", "κατσαρίδων"}}, 151 }, 152 { 153 s: "!@#$%^", 154 expected: []stringChunk{}, 155 tail: "!@#$%^", 156 }, 157 // Check cases where we see bad UTF-8 inputs. We should 158 // try to keep scanning until a reasonable value reappears. 159 { 160 s: "foo bar baz" + badString + "boom", 161 count: 4, 162 expected: []stringChunk{ 163 {"", "foo"}, 164 {" ", "bar"}, 165 {" ", "baz"}, 166 {badString, "boom"}, 167 }, 168 }, 169 { 170 s: badString + "boom", 171 count: 1, 172 expected: []stringChunk{ 173 {string([]byte{0xe0, 0x80, 0xaf}), "boom"}, 174 }, 175 }, 176 { 177 s: "boom" + badString, 178 count: 1, 179 expected: []stringChunk{ 180 {"", "boom"}, 181 }, 182 tail: badString, 183 }, 184 { 185 s: badString, 186 expected: []stringChunk{}, 187 tail: badString, 188 }, 189 { 190 // This should be too long to fit in the slice. 191 s: "1 2 3 4 5 6 7 8 9 10", 192 count: -1, 193 }, 194 } 195 196 for _, tc := range tests { 197 t.Run(tc.s, func(t *testing.T) { 198 textChunks := make([]stringChunk, 8) 199 count, tail := chunk(tc.s, textChunks) 200 if count != tc.count { 201 t.Errorf("expected %d, got %d", len(tc.expected), count) 202 } 203 if count < 0 { 204 return 205 } 206 if !reflect.DeepEqual(tc.expected, textChunks[:count]) { 207 t.Errorf("expected %v, got %v", tc.expected, textChunks[:count]) 208 } 209 if tail != tc.tail { 210 t.Errorf("expected tail %s, got %s", tail, tc.tail) 211 } 212 }) 213 } 214 } 215 216 func BenchmarkChunking(b *testing.B) { 217 for i := 0; i < b.N; i++ { 218 buf := make([]stringChunk, 8) 219 chunk("foo bar baz", buf) 220 } 221 }