Implement *strip data converter

This commit is contained in:
ionutboangiu
2023-10-04 12:27:47 -04:00
committed by Dan Christian Bogos
parent 4a812a294b
commit 3e56a5aac7
3 changed files with 186 additions and 0 deletions

View File

@@ -695,6 +695,7 @@ const (
VersionName = "Version"
MetaTenant = "*tenant"
ResourceUsage = "ResourceUsage"
MetaStrip = "*strip"
MetaDuration = "*duration"
MetaLibPhoneNumber = "*libphonenumber"
MetaTimeString = "*time_string"

View File

@@ -117,6 +117,8 @@ func NewDataConverter(params string) (conv DataConverter, err error) {
return NewRandomConverter(EmptyString)
}
return NewRandomConverter(params[len(MetaRandom)+1:])
case strings.HasPrefix(params, MetaStrip):
return NewStripConverter(params)
default:
return nil, fmt.Errorf("unsupported converter definition: <%s>", params)
}
@@ -586,3 +588,84 @@ func (jsnC JSONConverter) Convert(in any) (any, error) {
}
return string(b), nil
}
// StripConverter strips characters from the left or the right side of a string.
type StripConverter struct {
side string
substr string
amount int
}
// NewStripConverter creates a new StripConverter with the specified parameters.
// The input params string should have the format "<type>:<side>:<substr>:<amount>", where:
// - 'type' must be "*strip".
// - 'side' specifies the side of the string to strip, and it must be either "*left" or "*right".
// - 'substr' is the substring to be removed from the string.
// - 'amount' is the optional number of times 'substr' should be removed from the specified side.
//
// If 'amount' is omitted, it defaults to 1. If it is -1, all instances of 'substr' will be removed from the
// chosen side. If 'substr' is "*any", 'amount' characters will be removed from the specified side
// regardless of their value.
func NewStripConverter(params string) (DataConverter, error) {
sc := new(StripConverter)
paramSlice := strings.Split(params, InInFieldSep)
switch len(paramSlice) {
case 3:
sc.amount = 1
case 4:
var err error
sc.amount, err = strconv.Atoi(paramSlice[3])
if err != nil {
return nil, err
}
default:
return nil, errors.New("strip converter: invalid number of parameters (should have 3 or 4)")
}
if sc.side = paramSlice[1]; !IsSliceMember([]string{MetaLeft, MetaRight}, sc.side) {
return nil, errors.New("strip converter: invalid side parameter")
}
sc.substr = paramSlice[2]
if sc.substr == MetaAny && sc.amount == -1 {
return nil, errors.New("strip converter: invalid combination of substr and amount values")
}
if sc.substr != MetaAny && sc.amount != -1 {
sc.substr = strings.Repeat(paramSlice[2], sc.amount)
}
return sc, nil
}
// Convert trims the input string based on the StripConverter's configuration.
// It returns a CAST_FAILED error if the input is not a string.
func (sc StripConverter) Convert(in any) (any, error) {
str, ok := in.(string)
if !ok {
return nil, ErrCastFailed
}
switch sc.side {
case MetaLeft:
if sc.substr == MetaAny {
if sc.amount < len(str) {
return str[sc.amount:], nil
}
return str, nil
}
if sc.amount != -1 {
return strings.TrimPrefix(str, sc.substr), nil
}
return strings.TrimLeft(str, sc.substr), nil
case MetaRight:
if sc.substr == MetaAny {
if sc.amount < len(str) {
return str[:len(str)-sc.amount], nil
}
return str, nil
}
if sc.amount != -1 {
return strings.TrimSuffix(str, sc.substr), nil
}
return strings.TrimRight(str, sc.substr), nil
}
return str, nil
}

View File

@@ -1285,3 +1285,105 @@ func TestDataConverterConvertJSONOK(t *testing.T) {
t.Errorf("expected: <%+v>, \nreceived: <%+v>", exp, rcv)
}
}
func TestStripConverter(t *testing.T) {
tests := []struct {
name string
params string
input string
expected string
expectErr bool
}{
{
name: "Cut any leading 3 characters",
params: "*strip:*left:*any:3",
input: "000000435400",
expected: "000435400",
expectErr: false,
},
{
name: "Cut leading '00' twice",
params: "*strip:*left:00:2",
input: "000000435400",
expected: "00435400",
expectErr: false,
},
{
name: "Cut leading '00' default",
params: "*strip:*left:00",
input: "000000435400",
expected: "0000435400",
expectErr: false,
},
{
name: "Cut 8 trailing nils",
params: "*strip:*right:\u0000:8",
input: "password\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
expected: "password",
expectErr: false,
},
{
name: "Cut 8 trailing escaped nils",
params: "*strip:*right:\\u0000:8",
input: "password\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000",
expected: "password",
expectErr: false,
},
{
name: "Cut all trailing nils",
params: "*strip:*right:\u0000:-1",
input: "password\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
expected: "password",
expectErr: false,
},
{
name: "Cut all escaped trailing nils",
params: "*strip:*right:\\u0000:-1",
input: "password\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000",
expected: "password",
expectErr: false,
},
{
name: "Invalid substr and amount value combination",
params: "*strip:*right:*any:-1",
input: "test",
expected: "",
expectErr: true,
},
{
name: "Invalid nr of parameters",
params: "*strip:*right",
input: "test",
expected: "",
expectErr: true,
},
{
name: "Invalid side parameter",
params: "*strip:*up:abc:2",
input: "test",
expected: "",
expectErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sc, err := NewDataConverter(tt.params)
if (err != nil) != tt.expectErr {
t.Errorf("NewStripConverter error = %v, expectErr %v", err, tt.expectErr)
return
}
if tt.expectErr {
return
}
rcv, err := sc.Convert(tt.input)
if (err != nil) != tt.expectErr {
t.Errorf("Convert error = %v, expectErr %v", err, tt.expectErr)
return
}
if rcv != tt.expected {
t.Errorf("expected: %s, received: %s", tt.expected, rcv)
}
})
}
}