Files
openclaw/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatTranscriptExporterTests.swift
2026-07-29 10:36:38 -04:00

235 lines
7.3 KiB
Swift

import Testing
@testable import OpenClawChatUI
@Suite("ChatTranscriptExporter")
struct ChatTranscriptExporterTests {
@Test func `formats visible messages and attachments`() {
let messages = [
self.message(role: "system", text: "Hidden setup", timestamp: 0),
self.message(role: "user", text: "Hello, 世界 👋", timestamp: 0),
self.message(
role: "assistant",
text: """
<think>Do not export this reasoning.</think><final>
| Item | Value |
| --- | --- |
| code | `ok` |
```swift
print("hi")
```
</final>
""",
timestamp: 1000),
OpenClawChatMessage(
role: "user",
content: [
OpenClawChatMessageContent(
type: "attachment",
text: nil,
mimeType: "text/plain",
fileName: "résumé.txt",
content: nil),
],
timestamp: 2000),
self.message(role: "assistant", text: " ", timestamp: 3000),
]
let markdown = ChatTranscriptExporter.markdown(
sessionTitle: "Project 🐾",
sessionKey: "agent:main",
messages: messages)
#expect(markdown == """
# Project 🐾
### User — 1970-01-01T00:00:00Z
Hello, 世界 👋
### Assistant — 1970-01-01T00:00:01Z
| Item | Value |
| --- | --- |
| code | `ok` |
```swift
print("hi")
```
### User — 1970-01-01T00:00:02Z
_[attachment: résumé.txt]_
""")
}
@Test(arguments: [
"file", "attachment", "image", "audio", "video",
"FILE", "ATTACHMENT", "IMAGE", "AuDiO", "ViDeO",
])
func `classifies gateway media and historical file attachments consistently`(type: String) {
let content = OpenClawChatMessageContent(
type: type,
text: nil,
mimeType: nil,
fileName: nil,
content: nil)
#expect(content.isInlineAttachment)
}
@Test(arguments: ["text", "canvas", "toolCall", "tool_result"])
func `does not classify unrelated content as an attachment`(type: String) {
let content = OpenClawChatMessageContent(
type: type,
text: nil,
mimeType: "image/png",
fileName: "not-an-attachment.png",
content: nil)
#expect(!content.isInlineAttachment)
}
@Test func `does not classify content without a type as an attachment`() {
let content = OpenClawChatMessageContent(
type: nil,
text: nil,
mimeType: "image/png",
fileName: "not-an-attachment.png",
content: nil)
#expect(!content.isInlineAttachment)
}
@Test(arguments: ["user", "assistant"], ["image", "audio", "video", "IMAGE", "AuDiO", "ViDeO"])
func `exports canonical media-only messages`(role: String, type: String) {
let isAudio = type.lowercased() == "audio"
let isVideo = type.lowercased() == "video"
let filename = isAudio ? "voice-note.m4a" : isVideo ? "clip.mp4" : "photo.png"
let message = OpenClawChatMessage(
role: role,
content: [
OpenClawChatMessageContent(
type: type,
text: nil,
mimeType: isAudio ? "audio/mp4" : isVideo ? "video/mp4" : "image/png",
fileName: filename,
content: nil),
],
timestamp: 0)
let markdown = ChatTranscriptExporter.markdown(
sessionTitle: "Media chat",
sessionKey: "agent:main",
messages: [message])
#expect(markdown == """
# Media chat
### \(role == "user" ? "User" : "Assistant") — 1970-01-01T00:00:00Z
_[attachment: \(filename)]_
""")
}
@Test(arguments: ["image", "audio", "IMAGE", "AuDiO"])
func `preserves canonical media alongside message text`(type: String) {
let isAudio = type.lowercased() == "audio"
let filename = isAudio ? "voice-note.m4a" : "photo.png"
let message = OpenClawChatMessage(
role: "user",
content: [
OpenClawChatMessageContent(
type: "text",
text: "Here is the attachment.",
mimeType: nil,
fileName: nil,
content: nil),
OpenClawChatMessageContent(
type: type,
text: nil,
mimeType: isAudio ? "audio/mp4" : "image/png",
fileName: filename,
content: nil),
],
timestamp: 0)
let markdown = ChatTranscriptExporter.markdown(
sessionTitle: "Media chat",
sessionKey: "agent:main",
messages: [message])
#expect(markdown == """
# Media chat
### User — 1970-01-01T00:00:00Z
Here is the attachment.
_[attachment: \(filename)]_
""")
}
@Test(arguments: ["canvas", "toolCall", "tool_result"])
func `does not export non-attachment content as media`(type: String) {
let message = OpenClawChatMessage(
role: "assistant",
content: [
OpenClawChatMessageContent(
type: type,
text: nil,
mimeType: "image/png",
fileName: "not-an-attachment.png",
content: nil),
],
timestamp: 0)
#expect(ChatTranscriptExporter.markdown(
sessionTitle: "Media chat",
sessionKey: "agent:main",
messages: [message]) == "# Media chat\n")
}
@Test func `sanitizes filename`() {
#expect(
ChatTranscriptExporter.filename(
sessionTitle: " Project / Q3: \"Résumé\"? ",
sessionKey: "fallback") == "Project-Q3-Résumé.md")
#expect(
ChatTranscriptExporter.filename(
sessionTitle: "///",
sessionKey: "fallback") == "fallback.md")
let emojiFilename = ChatTranscriptExporter.filename(
sessionTitle: String(repeating: "🐾", count: 200),
sessionKey: "fallback")
#expect(emojiFilename.utf8.count <= 243)
#expect(emojiFilename.hasSuffix(".md"))
}
@Test func `empty transcript contains header only`() {
#expect(
ChatTranscriptExporter.markdown(
sessionTitle: nil,
sessionKey: "agent:main",
messages: []) == "# agent:main\n")
}
private func message(role: String, text: String, timestamp: Double) -> OpenClawChatMessage {
OpenClawChatMessage(
role: role,
content: [
OpenClawChatMessageContent(
type: "text",
text: text,
mimeType: nil,
fileName: nil,
content: nil),
],
timestamp: timestamp)
}
}