diff --git a/internal/im/content_rewrite_test.go b/internal/im/content_rewrite_test.go index 2470d42c..0450fd21 100644 --- a/internal/im/content_rewrite_test.go +++ b/internal/im/content_rewrite_test.go @@ -2,6 +2,7 @@ package im import ( "context" + "regexp" "strings" "testing" @@ -231,6 +232,28 @@ func TestRewriteStorageURLs_COSPathNotSignedAsLocalKey(t *testing.T) { } } +func TestFindIncompleteMarkdownImage(t *testing.T) { + tests := []struct { + name string + in string + want int + }{ + {"complete image", "![img](local://1/a.png)", -1}, + {"complete then text", "![img](local://1/a.png) trailing", -1}, + {"truncated provider URL in image", `![知识助理"知识库"管理视图界面](minio://wizard-test/10000/exports/c91cf852`, 0}, + {"open paren only", "text ![alt](", 5}, + {"bare provider suffix without markdown", "text minio://wizard-test/10000/exp", -1}, + {"two images complete", "![a](local://1/a.png) ![b](local://1/b.png)", -1}, + {"first complete second incomplete", "![a](local://1/a.png) ![b](minio://part", 22}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := findIncompleteMarkdownImage(tt.in) + assert.Equal(t, tt.want, got, "findIncompleteMarkdownImage(%q)", tt.in) + }) + } +} + func TestHoldbackCutoff(t *testing.T) { tests := []struct { name string @@ -240,13 +263,17 @@ func TestHoldbackCutoff(t *testing.T) { { "no holdback needed", "plain text with complete ![img](local://1/img.png) content", - // URL is terminated by `)` then space → no holdback - -1, // placeholder, computed below + -1, }, { - "truncated URL", + "truncated URL inside markdown image", "text ![img](local://1/abc/im", - 12, + 5, // hold back from ![ — not from local:// + }, + { + "truncated markdown image with quotes in alt", + "### 2\n![知识助理\"知识库\"管理视图界面](minio://wizard-test/10000/exports/c91cf852", + -2, // computed via strings.Index below }, { "truncated XML", @@ -254,19 +281,179 @@ func TestHoldbackCutoff(t *testing.T) { 5, }, { - "both truncated, URL earlier", + "both truncated, XML earlier", ", , or tag // that reaches the end of the string without a closing '>'. var incompleteXMLTagRe = regexp.MustCompile( @@ -155,7 +171,9 @@ func findIncompleteXMLTag(s string) int { // chunk, or len(chunk) if the chunk is safe to flush entirely. func holdbackCutoff(chunk string) int { cutoff := len(chunk) - if idx := findIncompleteStorageURL(chunk); idx >= 0 && idx < cutoff { + if idx := findIncompleteMarkdownImage(chunk); idx >= 0 && idx < cutoff { + cutoff = idx + } else if idx := findIncompleteStorageURL(chunk); idx >= 0 && idx < cutoff { cutoff = idx } if idx := findIncompleteXMLTag(chunk); idx >= 0 && idx < cutoff {