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  }