Adding upstream version 2.5.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c71cb8b61d
commit
982828099e
783 changed files with 150650 additions and 0 deletions
474
analysis/datetime/percent/percent_test.go
Normal file
474
analysis/datetime/percent/percent_test.go
Normal file
|
@ -0,0 +1,474 @@
|
|||
// Copyright (c) 2023 Couchbase, Inc.
|
||||
//
|
||||
// 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 percent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/blevesearch/bleve/v2/analysis"
|
||||
)
|
||||
|
||||
func TestConversionFromPercentStyle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // Added name field
|
||||
input string
|
||||
output string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "basic YMD",
|
||||
input: "%Y-%m-%d",
|
||||
output: "2006-01-02",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "YMD with double percent and literal T",
|
||||
input: "%Y/%m%%%%%dT%H%M:%S",
|
||||
output: "2006/01%%02T1504:05",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "YMD T HMS Z z",
|
||||
input: "%Y-%m-%dT%H:%M:%S %Z%z",
|
||||
output: "2006-01-02T15:04:05 MSTZ0700",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Full month, padded day/hour, am/pm, z:M",
|
||||
input: "%B %e, %Y %l:%i %P %z:M",
|
||||
output: "January 2, 2006 3:4 pm Z07:00",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Long format with literals and timezone literal :S",
|
||||
input: "Hour %H Minute %Mseconds %S.%N Timezone:%Z:S, Weekday %a; Day %d Month %b, Year %y",
|
||||
output: "Hour 15 Minute 04seconds 05.999999999 Timezone:MST:S, Weekday Mon; Day 02 Month Jan, Year 06",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "YMD T HMS with nanoseconds",
|
||||
input: "%Y-%m-%dT%H:%M:%S.%N",
|
||||
output: "2006-01-02T15:04:05.999999999",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z",
|
||||
input: "%H:%M:%S %Z %z",
|
||||
output: "15:04:05 MST Z0700",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z literal colon",
|
||||
input: "%H:%M:%S %Z %z:",
|
||||
output: "15:04:05 MST Z0700:",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z:M",
|
||||
input: "%H:%M:%S %Z %z:M",
|
||||
output: "15:04:05 MST Z07:00",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z:S",
|
||||
input: "%H:%M:%S %Z %z:S",
|
||||
output: "15:04:05 MST Z07:00:00",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z: literal A",
|
||||
input: "%H:%M:%S %Z %z:A",
|
||||
output: "15:04:05 MST Z0700:A",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z z literal M",
|
||||
input: "%H:%M:%S %Z %zM",
|
||||
output: "15:04:05 MST Z0700M",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z zH",
|
||||
input: "%H:%M:%S %Z %zH",
|
||||
output: "15:04:05 MST Z07",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "HMS Z zS",
|
||||
input: "%H:%M:%S %Z %zS",
|
||||
output: "15:04:05 MST Z070000",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Complex combination z zS z: zH",
|
||||
input: "%H:%M:%S %Z %z%Z %zS%z:%zH",
|
||||
output: "15:04:05 MST Z0700MST Z070000Z0700:Z07",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z at end",
|
||||
input: "%Y-%m-%d %z",
|
||||
output: "2006-01-02 Z0700",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z: at end",
|
||||
input: "%Y-%m-%d %z:",
|
||||
output: "2006-01-02 Z0700:",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "zH at end",
|
||||
input: "%Y-%m-%d %zH",
|
||||
output: "2006-01-02 Z07",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "zS at end",
|
||||
input: "%Y-%m-%d %zS",
|
||||
output: "2006-01-02 Z070000",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z:M at end",
|
||||
input: "%Y-%m-%d %z:M",
|
||||
output: "2006-01-02 Z07:00",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z:S at end",
|
||||
input: "%Y-%m-%d %z:S",
|
||||
output: "2006-01-02 Z07:00:00",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z followed by literal X",
|
||||
input: "%Y-%m-%d %zX",
|
||||
output: "2006-01-02 Z0700X",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "z: followed by literal X",
|
||||
input: "%Y-%m-%d %z:X",
|
||||
output: "2006-01-02 Z0700:X",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Invalid specifier T",
|
||||
input: "%Y-%m-%d%T%H:%M:%S %ZM",
|
||||
output: "",
|
||||
err: fmt.Errorf("invalid format string, unknown format specifier: T"),
|
||||
},
|
||||
{
|
||||
name: "Ends with %",
|
||||
input: "%Y-%m-%dT%H:%M:%S %ZM%",
|
||||
output: "",
|
||||
err: fmt.Errorf("invalid format string, expected character after %%"),
|
||||
},
|
||||
{
|
||||
name: "Just %",
|
||||
input: "%",
|
||||
output: "",
|
||||
err: fmt.Errorf("invalid format string, expected character after %%"),
|
||||
},
|
||||
{
|
||||
name: "Just %%",
|
||||
input: "%%",
|
||||
output: "%",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Unknown specifier x",
|
||||
input: "%x",
|
||||
output: "",
|
||||
err: fmt.Errorf("invalid format string, unknown format specifier: x"),
|
||||
},
|
||||
{
|
||||
name: "Literal prefix",
|
||||
input: "literal %Y",
|
||||
output: "literal 2006",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Literal suffix",
|
||||
input: "%Y literal",
|
||||
output: "2006 literal",
|
||||
err: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
out, err := parseFormatString(test.input)
|
||||
|
||||
// Enhanced Error Check:
|
||||
expectedErrStr := ""
|
||||
if test.err != nil {
|
||||
expectedErrStr = test.err.Error()
|
||||
}
|
||||
actualErrStr := ""
|
||||
if err != nil {
|
||||
actualErrStr = err.Error()
|
||||
}
|
||||
|
||||
if expectedErrStr != actualErrStr {
|
||||
// Provide more detailed output if errors don't match as strings
|
||||
t.Fatalf("error mismatch:\nExpected error: %q\nGot error : %q", expectedErrStr, actualErrStr)
|
||||
}
|
||||
|
||||
// Original error presence check (redundant if string check passes, but safe to keep)
|
||||
if (err != nil && test.err == nil) || (err == nil && test.err != nil) {
|
||||
t.Fatalf("presence mismatch: expected error %v, got error %v", test.err, err)
|
||||
}
|
||||
|
||||
// Check output matching only if no error was expected/occurred
|
||||
if err == nil && test.err == nil && out != test.output {
|
||||
t.Fatalf("output mismatch: expected '%v', got '%v'", test.output, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeParser_ParseDateTime(t *testing.T) {
|
||||
// Pre-create some parsers with known Go layouts
|
||||
parser1 := New([]string{"2006-01-02", "01/02/2006"}) // YYYY-MM-DD, MM/DD/YYYY
|
||||
parser2 := New([]string{"15:04:05"}) // HH:MM:SS
|
||||
parserEmpty := New([]string{}) // No layouts
|
||||
|
||||
// Define expected time values
|
||||
time1, _ := time.Parse("2006-01-02", "2023-10-27")
|
||||
time2, _ := time.Parse("01/02/2006", "10/27/2023")
|
||||
time3, _ := time.Parse("15:04:05", "14:30:00")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
parser *DateTimeParser
|
||||
input string
|
||||
expectTime time.Time
|
||||
expectLayout string
|
||||
expectErr error
|
||||
}{
|
||||
{
|
||||
name: "match first layout",
|
||||
parser: parser1,
|
||||
input: "2023-10-27",
|
||||
expectTime: time1,
|
||||
expectLayout: "2006-01-02",
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "match second layout",
|
||||
parser: parser1,
|
||||
input: "10/27/2023",
|
||||
expectTime: time2,
|
||||
expectLayout: "01/02/2006",
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "no matching layout",
|
||||
parser: parser1,
|
||||
input: "14:30:00", // Matches parser2's layout, not parser1's
|
||||
expectTime: time.Time{},
|
||||
expectLayout: "",
|
||||
expectErr: analysis.ErrInvalidDateTime,
|
||||
},
|
||||
{
|
||||
name: "match only layout",
|
||||
parser: parser2,
|
||||
input: "14:30:00",
|
||||
expectTime: time3,
|
||||
expectLayout: "15:04:05",
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid date format for layout",
|
||||
parser: parser1,
|
||||
input: "27-10-2023", // Wrong separators
|
||||
expectTime: time.Time{},
|
||||
expectLayout: "",
|
||||
expectErr: analysis.ErrInvalidDateTime, // time.Parse fails on all, returns ErrInvalidDateTime
|
||||
},
|
||||
{
|
||||
name: "empty input",
|
||||
parser: parser1,
|
||||
input: "",
|
||||
expectTime: time.Time{},
|
||||
expectLayout: "",
|
||||
expectErr: analysis.ErrInvalidDateTime,
|
||||
},
|
||||
{
|
||||
name: "parser with no layouts",
|
||||
parser: parserEmpty,
|
||||
input: "2023-10-27",
|
||||
expectTime: time.Time{},
|
||||
expectLayout: "",
|
||||
expectErr: analysis.ErrInvalidDateTime,
|
||||
},
|
||||
{
|
||||
name: "not a date string",
|
||||
parser: parser1,
|
||||
input: "hello world",
|
||||
expectTime: time.Time{},
|
||||
expectLayout: "",
|
||||
expectErr: analysis.ErrInvalidDateTime,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
gotTime, gotLayout, gotErr := test.parser.ParseDateTime(test.input)
|
||||
|
||||
// Check error
|
||||
if !reflect.DeepEqual(gotErr, test.expectErr) {
|
||||
t.Fatalf("error mismatch:\nExpected: %v\nGot: %v", test.expectErr, gotErr)
|
||||
}
|
||||
|
||||
// Check time only if no error expected
|
||||
if test.expectErr == nil {
|
||||
if !gotTime.Equal(test.expectTime) {
|
||||
t.Errorf("time mismatch:\nExpected: %v\nGot: %v", test.expectTime, gotTime)
|
||||
}
|
||||
if gotLayout != test.expectLayout {
|
||||
t.Errorf("layout mismatch:\nExpected: %q\nGot: %q", test.expectLayout, gotLayout)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDateTimeParserConstructor(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config map[string]interface{}
|
||||
expectLayouts []string // Expected Go layouts after parsing
|
||||
expectErr error
|
||||
}{
|
||||
{
|
||||
name: "valid config with multiple layouts",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%Y-%m-%d", "%H:%M:%S %Z"},
|
||||
},
|
||||
expectLayouts: []string{"2006-01-02", "15:04:05 MST"},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "valid config with single layout",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%Y/%m/%d %z:M"},
|
||||
},
|
||||
expectLayouts: []string{"2006/01/02 Z07:00"},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "valid config with complex layout",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%a, %d %b %Y %H:%M:%S %zH"},
|
||||
},
|
||||
expectLayouts: []string{"Mon, 02 Jan 2006 15:04:05 Z07"},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "config missing layouts key",
|
||||
config: map[string]interface{}{
|
||||
"other_key": "value",
|
||||
},
|
||||
expectLayouts: nil,
|
||||
expectErr: fmt.Errorf("must specify layouts"),
|
||||
},
|
||||
{
|
||||
name: "config layouts not a slice",
|
||||
config: map[string]interface{}{
|
||||
"layouts": "not-a-slice", // Value is a string
|
||||
},
|
||||
expectLayouts: nil,
|
||||
// Update the expected error message
|
||||
expectErr: fmt.Errorf("must specify layouts"),
|
||||
},
|
||||
{
|
||||
name: "config layouts contains non-string",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%Y-%m-%d", 123},
|
||||
},
|
||||
// Should process the valid string, ignore the int
|
||||
expectLayouts: []string{"2006-01-02"},
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "config layouts contains invalid percent format",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%Y-%m-%d", "%x"}, // %x is invalid
|
||||
},
|
||||
expectLayouts: nil,
|
||||
expectErr: fmt.Errorf("invalid format string, unknown format specifier: x"),
|
||||
},
|
||||
{
|
||||
name: "config layouts contains format ending in %",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{"%Y-%m-%d", "%H:%M:%"},
|
||||
},
|
||||
expectLayouts: nil,
|
||||
expectErr: fmt.Errorf("invalid format string, expected character after %%"),
|
||||
},
|
||||
{
|
||||
name: "config with empty layouts slice",
|
||||
config: map[string]interface{}{
|
||||
"layouts": []interface{}{},
|
||||
},
|
||||
expectLayouts: []string{}, // Expect an empty slice, not nil
|
||||
expectErr: nil,
|
||||
},
|
||||
{
|
||||
name: "nil config",
|
||||
config: nil,
|
||||
expectLayouts: nil,
|
||||
expectErr: fmt.Errorf("must specify layouts"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// Cache is not used by this constructor, so nil is fine
|
||||
parserIntf, err := DateTimeParserConstructor(test.config, nil)
|
||||
|
||||
// Check error
|
||||
// Use string comparison for errors as they might be created differently
|
||||
expectedErrStr := ""
|
||||
if test.expectErr != nil {
|
||||
expectedErrStr = test.expectErr.Error()
|
||||
}
|
||||
actualErrStr := ""
|
||||
if err != nil {
|
||||
actualErrStr = err.Error()
|
||||
}
|
||||
if expectedErrStr != actualErrStr {
|
||||
t.Fatalf("error mismatch:\nExpected: %q\nGot: %q", expectedErrStr, actualErrStr)
|
||||
}
|
||||
|
||||
// Check layouts only if no error expected
|
||||
if test.expectErr == nil {
|
||||
// Type assert to access the layouts field
|
||||
parser, ok := parserIntf.(*DateTimeParser)
|
||||
if !ok {
|
||||
t.Fatalf("constructor did not return a *DateTimeParser")
|
||||
}
|
||||
if !reflect.DeepEqual(parser.layouts, test.expectLayouts) {
|
||||
t.Errorf("layouts mismatch:\nExpected: %v\nGot: %v", test.expectLayouts, parser.layouts)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue