Update *strip converter implementation and its tests

Added in-depth comments to the constructor.
Added test cases for most edge cases (if not all).
Updated the test to verify not only if an error occurs, but to also
check whether it matches the one we expect.
Added 3 more sanity checks that were missed.
This commit is contained in:
ionutboangiu
2023-10-09 11:08:15 -04:00
committed by Dan Christian Bogos
parent 36e43beca8
commit 6cfb934c9b
2 changed files with 103 additions and 19 deletions

View File

@@ -591,15 +591,37 @@ func (jsnC JSONConverter) Convert(in any) (any, error) {
// StripConverter strips the prefix, the suffix or both from a string.
type StripConverter struct {
side string
substr string
amount int
side string // side represents which part of the string to strip: prefix, suffix, or both.
substr string // substr represents the substring to be removed from the string.
amount int // amount represents the number of characters to be removed from the string.
}
// NewStripConverter creates a new StripConverter with the specified parameters.
// NewStripConverter initializes and returns a new StripConverter with configurations
// based on the provided parameters in the input string. Each parameter in the input
// string should be separated by ':'.
//
// The input string must follow one of the following formats:
// 1. "*strip:<side>:<amount>"
// 2. "*strip:<side>:<substring>[:<amount>]"
// 3. "*strip:<side>:*char:<substring>[:<amount>]"
//
// Explanation of placeholders:
// - <side>: Specifies which part of the string to strip. Must be one of "*prefix", "*suffix", or "*both".
// - <substring>: Identifies the substring to remove. It can be a specific string, "*nil" for null characters,
// "*space" for spaces, or any other character.
// - <amount> (optional): Determines the number of characters to remove. If omitted, all instances of <substring>
// are removed.
//
// Examples:
// - "*strip:*prefix:5": Removes the first 5 characters from the string's prefix.
// - "*strip:*suffix:*nil": Eliminates all trailing null characters in the string.
// - "*strip:*both:*space:2": Clears 2 spaces from both the prefix and suffix of the string.
// - "*strip:*suffix:*char:abc": Removes the substring "abc" from the suffix of the string.
// - "*strip:*prefix:*char:abc:2": Strips the substring "abc" from the prefix of the string, repeated 2 times.
func NewStripConverter(params string) (DataConverter, error) {
paramSlice := strings.Split(params, InInFieldSep)
if len(paramSlice) < 3 || len(paramSlice) > 5 {
paramCount := len(paramSlice)
if paramCount < 3 || paramCount > 5 {
return nil, errors.New("strip converter: invalid number of parameters (should have 3, 4 or 5)")
}
sc := StripConverter{
@@ -612,12 +634,15 @@ func NewStripConverter(params string) (DataConverter, error) {
case EmptyString:
return nil, errors.New("strip converter: substr parameter cannot be empty")
case MetaNil, MetaSpace:
if paramCount == 5 {
return nil, errors.New("strip converter: cannot have 5 params in *nil/*space case")
}
if sc.substr == MetaNil {
sc.substr = "\u0000"
} else {
sc.substr = " "
}
if len(paramSlice) == 4 {
if paramCount == 4 {
sc.amount, err = strconv.Atoi(paramSlice[3])
if err != nil {
return nil, fmt.Errorf("strip converter: invalid amount parameter (%w)", err)
@@ -625,11 +650,11 @@ func NewStripConverter(params string) (DataConverter, error) {
sc.substr = strings.Repeat(sc.substr, sc.amount)
}
case MetaChar:
if len(paramSlice) < 4 {
return nil, errors.New("strip converter: usage of *char implies the need of 4 or 5 params")
if paramCount < 4 || paramSlice[3] == EmptyString {
return nil, errors.New("strip converter: usage of *char implies the need of 4 or 5 non-empty params")
}
sc.substr = paramSlice[3] // should probably return error if empty
if len(paramSlice) == 5 {
sc.substr = paramSlice[3]
if paramCount == 5 {
sc.amount, err = strconv.Atoi(paramSlice[4])
if err != nil {
return nil, fmt.Errorf("strip converter: invalid amount parameter (%w)", err)
@@ -637,13 +662,15 @@ func NewStripConverter(params string) (DataConverter, error) {
sc.substr = strings.Repeat(sc.substr, sc.amount)
}
default:
if paramCount > 3 {
return nil, errors.New("strip converter: just the amount specified, cannot have more than 3 params")
}
sc.amount, err = strconv.Atoi(paramSlice[2])
if err != nil {
return nil, fmt.Errorf("strip converter: invalid amount parameter (%w)", err)
}
sc.substr = ""
}
return sc, nil
}

View File

@@ -1468,7 +1468,7 @@ func TestStripConverter(t *testing.T) {
name: "Empty third parameter",
params: "*strip:*prefix:",
input: "TEST",
expected: "",
expected: "strip converter: substr parameter cannot be empty",
constructorErr: true,
convertErr: false,
},
@@ -1476,15 +1476,15 @@ func TestStripConverter(t *testing.T) {
name: "Invalid side parameter",
params: "*strip:*invalid:*nil",
input: "TEST",
expected: "",
expected: "strip converter: invalid side parameter",
constructorErr: false,
convertErr: true,
},
{
name: "Invalid nr. of parameters",
name: "Invalid nr. of params *char",
params: "*strip:*prefix:*char:*nil:abc:3",
input: "TEST",
expected: "",
expected: "strip converter: invalid number of parameters (should have 3, 4 or 5)",
constructorErr: true,
convertErr: false,
},
@@ -1492,7 +1492,7 @@ func TestStripConverter(t *testing.T) {
name: "Invalid amount parameter",
params: "*strip:*prefix:*char:0:three",
input: "000TEST",
expected: "",
expected: "strip converter: invalid amount parameter (strconv.Atoi: parsing \"three\": invalid syntax)",
constructorErr: true,
convertErr: false,
},
@@ -1520,25 +1520,82 @@ func TestStripConverter(t *testing.T) {
constructorErr: false,
convertErr: false,
},
{
name: "*char missing substring case 1",
params: "*strip:*prefix:*char",
input: "12345TEST",
expected: "strip converter: usage of *char implies the need of 4 or 5 non-empty params",
constructorErr: true,
convertErr: false,
},
{
name: "*char missing substring case 2",
params: "*strip:*prefix:*char::2",
input: "12345TEST",
expected: "strip converter: usage of *char implies the need of 4 or 5 non-empty params",
constructorErr: true,
convertErr: false,
},
{
name: "*char missing substring case 3",
params: "*strip:*prefix:*char:",
input: "12345TEST",
expected: "strip converter: usage of *char implies the need of 4 or 5 non-empty params",
constructorErr: true,
convertErr: false,
},
{
name: "*nil/*space too many parameters",
params: "*strip:*prefix:*nil:5:12345",
input: "12345TEST",
expected: "strip converter: cannot have 5 params in *nil/*space case",
constructorErr: true,
convertErr: false,
},
{
name: "third param numeric with too many params case 1",
params: "*strip:*prefix:1:1",
input: "12345TEST",
expected: "strip converter: just the amount specified, cannot have more than 3 params",
constructorErr: true,
convertErr: false,
},
{
name: "third param numeric with too many params case 2",
params: "*strip:*prefix:1:12345:1",
input: "12345TEST",
expected: "strip converter: just the amount specified, cannot have more than 3 params",
constructorErr: true,
convertErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sc, err := NewDataConverter(tt.params)
if (err != nil) != tt.constructorErr {
t.Errorf("NewStripConverter error = %v, constructorErr %v", err, tt.constructorErr)
t.Errorf("NewStripConverter() error = %v, constructorErr %v", err, tt.constructorErr)
return
}
if tt.constructorErr {
if err.Error() != tt.expected {
t.Errorf("expected error message: %v, received: %v", tt.expected, err.Error())
}
return
}
rcv, err := sc.Convert(tt.input)
if (err != nil) != tt.convertErr {
t.Errorf("Convert error = %v, convertErr %v", err, tt.convertErr)
t.Errorf("Convert() error = %v, convertErr %v", err, tt.convertErr)
return
}
if tt.convertErr {
if err.Error() != tt.expected {
t.Errorf("expected error message: %s, received: %s", tt.expected, err.Error())
}
return
}
if rcv != tt.expected {
t.Errorf("expected: %s, received: %s", tt.expected, rcv)
t.Errorf("expected: %q, received: %q", tt.expected, rcv)
}
})
}