@@ -164,6 +164,78 @@ func TestConvertLineMessagePreservesMentionsForSticonFallback(t *testing.T) {
164164 }
165165}
166166
167+ func TestConvertLineMessageUsesUTF16MentionOffsets (t * testing.T ) {
168+ text := "🙂 嗨 @กิ๊ก!"
169+ userMXID := id .UserID ("@user:example.com" )
170+ lc := & LineClient {
171+ Mid : "self-mid" ,
172+ UserLogin : & bridgev2.UserLogin {
173+ UserLogin : & database.UserLogin {UserMXID : userMXID },
174+ Bridge : & bridgev2.Bridge {Log : zerolog .New (io .Discard )},
175+ },
176+ }
177+ data := line.Message {
178+ ContentType : int (ContentText ),
179+ ContentMetadata : map [string ]string {
180+ "MENTION" : `{"MENTIONEES":[{"M":"self-mid","S":"5","E":"10"}]}` ,
181+ },
182+ }
183+
184+ converted , err := lc .convertLineMessage (t .Context (), nil , nil , data , text , text , false )
185+ if err != nil {
186+ t .Fatalf ("convertLineMessage returned error: %v" , err )
187+ }
188+ if converted == nil || len (converted .Parts ) != 1 || converted .Parts [0 ].Content == nil {
189+ t .Fatalf ("convertLineMessage returned %#v, want one message part" , converted )
190+ }
191+ content := converted .Parts [0 ].Content
192+ if content .Body != text {
193+ t .Fatalf ("Body = %q, want %q" , content .Body , text )
194+ }
195+ if content .Mentions == nil || len (content .Mentions .UserIDs ) != 1 || content .Mentions .UserIDs [0 ] != userMXID {
196+ t .Fatalf ("Mentions = %#v, want user %s" , content .Mentions , userMXID )
197+ }
198+ expectedLink := `<a href="https://matrix.to/#/@user:example.com">@กิ๊ก</a>`
199+ if ! strings .Contains (content .FormattedBody , expectedLink ) {
200+ t .Fatalf ("FormattedBody = %q, want link %q" , content .FormattedBody , expectedLink )
201+ }
202+ }
203+
204+ func TestConvertLineMessageUsesUTF16RoomMentionOffsets (t * testing.T ) {
205+ text := "🙂 嗨 @everyone!"
206+ lc := & LineClient {
207+ UserLogin : & bridgev2.UserLogin {
208+ UserLogin : & database.UserLogin {UserMXID : "@user:example.com" },
209+ Bridge : & bridgev2.Bridge {Log : zerolog .New (io .Discard )},
210+ },
211+ }
212+ data := line.Message {
213+ ContentType : int (ContentText ),
214+ ContentMetadata : map [string ]string {
215+ "MENTION" : `{"MENTIONEES":[{"A":"1","S":"5","E":"14"}]}` ,
216+ },
217+ }
218+
219+ converted , err := lc .convertLineMessage (t .Context (), nil , nil , data , text , text , false )
220+ if err != nil {
221+ t .Fatalf ("convertLineMessage returned error: %v" , err )
222+ }
223+ if converted == nil || len (converted .Parts ) != 1 || converted .Parts [0 ].Content == nil {
224+ t .Fatalf ("convertLineMessage returned %#v, want one message part" , converted )
225+ }
226+ content := converted .Parts [0 ].Content
227+ if content .Body != "🙂 嗨 @room!" {
228+ t .Fatalf ("Body = %q, want room mention replacement" , content .Body )
229+ }
230+ if content .Mentions == nil || ! content .Mentions .Room {
231+ t .Fatalf ("Mentions = %#v, want room mention" , content .Mentions )
232+ }
233+ expectedLink := `<a href="https://matrix.to/#/@room">@everyone</a>`
234+ if ! strings .Contains (content .FormattedBody , expectedLink ) {
235+ t .Fatalf ("FormattedBody = %q, want link %q" , content .FormattedBody , expectedLink )
236+ }
237+ }
238+
167239func TestDecryptMessageBodySkipsGeneratedFallbackWhenDecryptUnavailable (t * testing.T ) {
168240 msg := & line.Message {
169241 Text : "" ,
0 commit comments