Skip to content

Commit

Permalink
Use the new truncation in bytes functions to ensure strings are not b…
Browse files Browse the repository at this point in the history
…utchered

Signed-off-by: gotjosh <josue.abreu@gmail.com>
  • Loading branch information
gotjosh committed Nov 11, 2022
1 parent 7f94b16 commit f51f51e
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 12 deletions.
22 changes: 20 additions & 2 deletions notify/util.go
Expand Up @@ -20,6 +20,7 @@ import (
"io"
"net/http"
"net/url"
"strings"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
Expand Down Expand Up @@ -100,15 +101,32 @@ func TruncateInRunes(s string, n int) (string, bool) {

// TruncateInBytes truncates a string to fit the given size in Bytes.
func TruncateInBytes(s string, n int) (string, bool) {
// First, measure the string the w/o a to-rune conversion.
if len(s) <= n {
return s, false
}

// The truncationMarker itself is 3 bytes, we can't return any part of the string when it's less than 3.
if n <= 3 {
return string(s[:n]), true
switch n {
case 3:
return truncationMarker, true
default:
return strings.Repeat(".", n), true
}
}

// Now, to ensure we don't butcher the string we need to remove using runes.
r := []rune(s)
truncationTarget := n - 3

// Next, let's truncate the runes to the lower possible number.
truncatedRunes := r[:truncationTarget]
for len(string(truncatedRunes)) > truncationTarget {
truncatedRunes = r[:len(truncatedRunes)-1]
}

return string(s[:n-3]) + truncationMarker, true // In bytes, the truncation marker is 3 bytes.
return string(truncatedRunes) + truncationMarker, true
}

// TmplText is using monadic error handling in order to make string templating
Expand Down
18 changes: 9 additions & 9 deletions notify/util_test.go
Expand Up @@ -49,7 +49,7 @@ func TestTruncate(t *testing.T) {
in: "abcde",
n: 2,
runes: expect{out: "ab", trunc: true},
bytes: expect{out: "ab", trunc: true},
bytes: expect{out: "..", trunc: true},
},
{
in: "abcde",
Expand All @@ -73,25 +73,25 @@ func TestTruncate(t *testing.T) {
in: "a⌘cde",
n: 5,
runes: expect{out: "a⌘cde", trunc: false},
bytes: expect{out: "a\xe2…", trunc: true},
bytes: expect{out: "a…", trunc: true},
},
{
in: "a⌘cdef",
n: 5,
runes: expect{out: "a⌘cd…", trunc: true},
bytes: expect{out: "a\xe2…", trunc: true},
bytes: expect{out: "a…", trunc: true},
},
{
in: "世界cdef",
n: 3,
runes: expect{out: "世界c", trunc: true},
bytes: expect{out: "", trunc: true},
bytes: expect{out: "", trunc: true},
},
{
in: "❤️✅🚀🔥❌",
n: 4,
runes: expect{out: "❤️✅…", trunc: true},
bytes: expect{out: "\xe2…", trunc: true},
in: "❤️✅🚀🔥❌❤️✅🚀🔥❌❤️✅🚀🔥❌❤️✅🚀🔥❌",
n: 19,
runes: expect{out: "❤️✅🚀🔥❌❤️✅🚀🔥❌❤️✅🚀🔥❌…", trunc: true},
bytes: expect{out: "❤️✅🚀…", trunc: true},
},
}

Expand All @@ -117,8 +117,8 @@ func TestTruncate(t *testing.T) {

t.Run(fmt.Sprintf("%s(%s,%d)", fnName, tc.in, tc.n), func(t *testing.T) {
s, trunc := fn(tc.in, tc.n)
require.Equal(t, truncated, trunc)
require.Equal(t, out, s)
require.Equal(t, truncated, trunc)
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion notify/webex/webex.go
Expand Up @@ -94,7 +94,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
return false, err
}

message, truncated := notify.Truncate(message, maxMessageSize)
message, truncated := notify.TruncateInBytes(message, maxMessageSize)
if truncated {
level.Debug(n.logger).Log("msg", "message truncated due to exceeding maximum allowed length by webex", "truncated_message", message)
}
Expand Down

0 comments on commit f51f51e

Please sign in to comment.