diff --git a/core/stringx/node.go b/core/stringx/node.go index 4b6fb6e1..388e8f7b 100644 --- a/core/stringx/node.go +++ b/core/stringx/node.go @@ -102,6 +102,7 @@ func (n *node) find(chars []rune) []scope { func (n *node) longestMatch(chars []rune, start int) (used int, jump *node, matched bool) { cur := n var matchedNode *node + for i := start; i < len(chars); i++ { child, ok := cur.children[chars[i]] if ok { @@ -113,9 +114,11 @@ func (n *node) longestMatch(chars []rune, start int) (used int, jump *node, matc if matchedNode != nil { return matchedNode.depth, nil, true } + if n.end { return start, nil, true } + var jump *node for cur.fail != nil { jump, ok = cur.fail.children[chars[i]] @@ -127,16 +130,20 @@ func (n *node) longestMatch(chars []rune, start int) (used int, jump *node, matc if jump != nil { return i + 1 - jump.depth, jump, false } + return i + 1, nil, false } } - // this longest matched node + + // longest matched node if matchedNode != nil { return matchedNode.depth, nil, true } - // last mathed node + + // last matched node if n.end { return start, nil, true } + return len(chars), nil, false } diff --git a/core/stringx/node_test.go b/core/stringx/node_test.go index f9b8d1d0..260e21ab 100644 --- a/core/stringx/node_test.go +++ b/core/stringx/node_test.go @@ -6,6 +6,15 @@ import ( "github.com/stretchr/testify/assert" ) +func TestLongestMatchGuardedCondition(t *testing.T) { + n := new(node) + n.end = true + used, jump, matched := n.longestMatch([]rune(""), 0) + assert.Equal(t, 0, used) + assert.Nil(t, jump) + assert.True(t, matched) +} + func TestFuzzNodeCase1(t *testing.T) { keywords := []string{ "cs8Zh", diff --git a/core/stringx/replacer.go b/core/stringx/replacer.go index 3edcf9c2..5447b12d 100644 --- a/core/stringx/replacer.go +++ b/core/stringx/replacer.go @@ -1,6 +1,8 @@ package stringx -import "strings" +import ( + "strings" +) type ( // Replacer interface wraps the Replace method. @@ -31,9 +33,10 @@ func NewReplacer(mapping map[string]string) Replacer { // Replace replaces text with given substitutes. func (r *replacer) Replace(text string) string { var buf strings.Builder + var nextStart int target := []rune(text) cur := r.node - nextStart := 0 + for len(target) != 0 { used, jump, matched := cur.longestMatch(target, nextStart) if matched { @@ -53,5 +56,6 @@ func (r *replacer) Replace(text string) string { } } } + return buf.String() } diff --git a/core/stringx/replacer_fuzz_test.go b/core/stringx/replacer_fuzz_test.go index 2e9facbe..da81ad9c 100644 --- a/core/stringx/replacer_fuzz_test.go +++ b/core/stringx/replacer_fuzz_test.go @@ -1,5 +1,4 @@ //go:build go1.18 -// +build go1.18 package stringx diff --git a/core/stringx/replacer_test.go b/core/stringx/replacer_test.go index 0d3c4015..df35448b 100644 --- a/core/stringx/replacer_test.go +++ b/core/stringx/replacer_test.go @@ -60,6 +60,22 @@ func TestReplacer_ReplaceLongestMatching(t *testing.T) { assert.Equal(t, "东京在japan", replacer.Replace("日本的首都在日本")) } +func TestReplacer_ReplaceLongestOverlap(t *testing.T) { + keywords := map[string]string{ + "456": "def", + "abcd": "1234", + } + replacer := NewReplacer(keywords) + assert.Equal(t, "123def7", replacer.Replace("abcd567")) +} + +func TestReplacer_ReplaceLongestLonger(t *testing.T) { + mapping := map[string]string{ + "c": "3", + } + assert.Equal(t, "3d", NewReplacer(mapping).Replace("cd")) +} + func TestReplacer_ReplaceJumpToFail(t *testing.T) { mapping := map[string]string{ "bcdf": "1235", diff --git a/zrpc/internal/rpcserver_test.go b/zrpc/internal/rpcserver_test.go index db358b57..7cba1e3d 100644 --- a/zrpc/internal/rpcserver_test.go +++ b/zrpc/internal/rpcserver_test.go @@ -22,10 +22,11 @@ func TestRpcServer(t *testing.T) { Breaker: true, }, WithMetrics(metrics), WithRpcHealth(true)) server.SetName("mock") - var wg sync.WaitGroup + var wg, wgDone sync.WaitGroup var grpcServer *grpc.Server var lock sync.Mutex wg.Add(1) + wgDone.Add(1) go func() { err := server.Start(func(server *grpc.Server) { lock.Lock() @@ -35,6 +36,7 @@ func TestRpcServer(t *testing.T) { wg.Done() }) assert.Nil(t, err) + wgDone.Done() }() wg.Wait() @@ -43,6 +45,9 @@ func TestRpcServer(t *testing.T) { lock.Lock() grpcServer.GracefulStop() lock.Unlock() + + proc.WrapUp() + wgDone.Wait() } func TestRpcServer_WithBadAddress(t *testing.T) { @@ -58,6 +63,8 @@ func TestRpcServer_WithBadAddress(t *testing.T) { mock.RegisterDepositServiceServer(server, new(mock.DepositServer)) }) assert.NotNil(t, err) + + proc.WrapUp() } func TestRpcServer_buildUnaryInterceptor(t *testing.T) {