From dcbf8fa43742b69ea4a998220e92e8a54c1a98ab Mon Sep 17 00:00:00 2001 From: Peter Deng Date: Mon, 21 Aug 2023 23:34:08 +0800 Subject: [PATCH] [pkg/ottl] use IntGetter argument for Substring function (#25874) **Description:** use IntGetter argument for Substring function **Link to tracking Issue:** #25852 **Testing:** **Documentation:** --------- Co-authored-by: Antoine Toulme Co-authored-by: Tyler Helmuth <12352919+TylerHelmuth@users.noreply.github.com> --- .chloggen/ottl-substring-intgetter.yaml | 27 +++++ pkg/ottl/ottlfuncs/func_substring.go | 31 +++--- pkg/ottl/ottlfuncs/func_substring_test.go | 118 +++++++++++++++++----- 3 files changed, 137 insertions(+), 39 deletions(-) create mode 100644 .chloggen/ottl-substring-intgetter.yaml diff --git a/.chloggen/ottl-substring-intgetter.yaml b/.chloggen/ottl-substring-intgetter.yaml new file mode 100644 index 000000000000..09803104151c --- /dev/null +++ b/.chloggen/ottl-substring-intgetter.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: breaking + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: pkg/ottl + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: use IntGetter argument for Substring function + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [25852] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [api] diff --git a/pkg/ottl/ottlfuncs/func_substring.go b/pkg/ottl/ottlfuncs/func_substring.go index 43eedf9b2048..b1658a8dc608 100644 --- a/pkg/ottl/ottlfuncs/func_substring.go +++ b/pkg/ottl/ottlfuncs/func_substring.go @@ -12,8 +12,8 @@ import ( type SubstringArguments[K any] struct { Target ottl.StringGetter[K] `ottlarg:"0"` - Start int64 `ottlarg:"1"` - Length int64 `ottlarg:"2"` + Start ottl.IntGetter[K] `ottlarg:"1"` + Length ottl.IntGetter[K] `ottlarg:"2"` } func NewSubstringFactory[K any]() ottl.Factory[K] { @@ -27,18 +27,25 @@ func createSubstringFunction[K any](_ ottl.FunctionContext, oArgs ottl.Arguments return nil, fmt.Errorf("SubstringFactory args must be of type *SubstringArguments[K]") } - return substring(args.Target, args.Start, args.Length) + return substring(args.Target, args.Start, args.Length), nil } -func substring[K any](target ottl.StringGetter[K], start int64, length int64) (ottl.ExprFunc[K], error) { - if start < 0 { - return nil, fmt.Errorf("invalid start for substring function, %d cannot be negative", start) - } - if length <= 0 { - return nil, fmt.Errorf("invalid length for substring function, %d cannot be negative or zero", length) - } - +func substring[K any](target ottl.StringGetter[K], startGetter ottl.IntGetter[K], lengthGetter ottl.IntGetter[K]) ottl.ExprFunc[K] { return func(ctx context.Context, tCtx K) (interface{}, error) { + start, err := startGetter.Get(ctx, tCtx) + if err != nil { + return nil, err + } + if start < 0 { + return nil, fmt.Errorf("invalid start for substring function, %d cannot be negative", start) + } + length, err := lengthGetter.Get(ctx, tCtx) + if err != nil { + return nil, err + } + if length <= 0 { + return nil, fmt.Errorf("invalid length for substring function, %d cannot be negative or zero", length) + } val, err := target.Get(ctx, tCtx) if err != nil { return nil, err @@ -47,5 +54,5 @@ func substring[K any](target ottl.StringGetter[K], start int64, length int64) (o return nil, fmt.Errorf("invalid range for substring function, %d cannot be greater than the length of target string(%d)", start+length, len(val)) } return val[start : start+length], nil - }, nil + } } diff --git a/pkg/ottl/ottlfuncs/func_substring_test.go b/pkg/ottl/ottlfuncs/func_substring_test.go index 9e1580b20e83..1b659e9b6d76 100644 --- a/pkg/ottl/ottlfuncs/func_substring_test.go +++ b/pkg/ottl/ottlfuncs/func_substring_test.go @@ -16,8 +16,8 @@ func Test_substring(t *testing.T) { tests := []struct { name string target ottl.StringGetter[interface{}] - start int64 - length int64 + start ottl.IntGetter[interface{}] + length ottl.IntGetter[interface{}] expected interface{} }{ { @@ -27,8 +27,16 @@ func Test_substring(t *testing.T) { return "123456789", nil }, }, - start: 3, - length: 3, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, expected: "456", }, { @@ -38,15 +46,22 @@ func Test_substring(t *testing.T) { return "123456789", nil }, }, - start: 0, - length: 9, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(0), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(9), nil + }, + }, expected: "123456789", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exprFunc, err := substring(tt.target, tt.start, tt.length) - assert.NoError(t, err) + exprFunc := substring(tt.target, tt.start, tt.length) result, err := exprFunc(nil, nil) assert.NoError(t, err) assert.Equal(t, tt.expected, result) @@ -58,8 +73,8 @@ func Test_substring_validation(t *testing.T) { tests := []struct { name string target ottl.StringGetter[interface{}] - start int64 - length int64 + start ottl.IntGetter[interface{}] + length ottl.IntGetter[interface{}] }{ { name: "substring with result of empty string", @@ -68,8 +83,16 @@ func Test_substring_validation(t *testing.T) { return "123456789", nil }, }, - start: 0, - length: 0, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(0), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(0), nil + }, + }, }, { name: "substring with invalid start index", @@ -78,14 +101,24 @@ func Test_substring_validation(t *testing.T) { return "123456789", nil }, }, - start: -1, - length: 6, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(-1), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(6), nil + }, + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := substring(tt.target, tt.start, tt.length) + exprFunc := substring(tt.target, tt.start, tt.length) + result, err := exprFunc(nil, nil) assert.Error(t, err) + assert.Nil(t, result) }) } } @@ -94,8 +127,8 @@ func Test_substring_error(t *testing.T) { tests := []struct { name string target ottl.StringGetter[interface{}] - start int64 - length int64 + start ottl.IntGetter[interface{}] + length ottl.IntGetter[interface{}] }{ { name: "substring empty string", @@ -104,8 +137,16 @@ func Test_substring_error(t *testing.T) { return "", nil }, }, - start: 3, - length: 6, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(6), nil + }, + }, }, { name: "substring with invalid length index", @@ -114,8 +155,16 @@ func Test_substring_error(t *testing.T) { return "123456789", nil }, }, - start: 3, - length: 20, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(20), nil + }, + }, }, { name: "substring non-string", @@ -124,8 +173,16 @@ func Test_substring_error(t *testing.T) { return 123456789, nil }, }, - start: 3, - length: 6, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(6), nil + }, + }, }, { name: "substring nil string", @@ -134,14 +191,21 @@ func Test_substring_error(t *testing.T) { return nil, nil }, }, - start: 3, - length: 6, + start: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(3), nil + }, + }, + length: &ottl.StandardIntGetter[interface{}]{ + Getter: func(context.Context, interface{}) (interface{}, error) { + return int64(6), nil + }, + }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - exprFunc, err := substring(tt.target, tt.start, tt.length) - assert.NoError(t, err) + exprFunc := substring(tt.target, tt.start, tt.length) result, err := exprFunc(nil, nil) assert.Error(t, err) assert.Equal(t, nil, result)