Files

234 lines
6.4 KiB
Swift

import Foundation
import MLX
import MLXLMCommon
import MLXVLM
import XCTest
func assertEqual(
_ v1: Any, _ v2: Any, path: [String] = [], file: StaticString = #filePath, line: UInt = #line
) {
switch (v1, v2) {
case let (v1, v2) as (String, String):
XCTAssertEqual(v1, v2, file: file, line: line)
case let (v1, v2) as ([Any], [Any]):
XCTAssertEqual(
v1.count, v2.count, "Arrays not equal size at \(path)", file: file, line: line)
for (index, (v1v, v2v)) in zip(v1, v2).enumerated() {
assertEqual(v1v, v2v, path: path + [index.description], file: file, line: line)
}
case let (v1, v2) as ([String: any Sendable], [String: any Sendable]):
XCTAssertEqual(
v1.keys.sorted(), v2.keys.sorted(),
"\(String(describing: v1.keys.sorted())) and \(String(describing: v2.keys.sorted())) not equal at \(path)",
file: file, line: line)
for (k, v1v) in v1 {
if let v2v = v2[k] {
assertEqual(v1v, v2v, path: path + [k], file: file, line: line)
} else {
XCTFail("Missing value for \(k) at \(path)", file: file, line: line)
}
}
default:
XCTFail(
"Unable to compare \(String(describing: v1)) and \(String(describing: v2)) at \(path)",
file: file, line: line)
}
}
public class UserInputTests: XCTestCase {
public func testStandardConversion() {
let chat: [Chat.Message] = [
.system("You are a useful agent."),
.user("Tell me a story."),
]
let messages = DefaultMessageGenerator().generate(messages: chat)
let expected = [
[
"role": "system",
"content": "You are a useful agent.",
],
[
"role": "user",
"content": "Tell me a story.",
],
]
XCTAssertEqual(expected, messages as? [[String: String]])
}
public func testQwen2ConversionText() {
let chat: [Chat.Message] = [
.system("You are a useful agent."),
.user("Tell me a story."),
]
let messages = Qwen2VLMessageGenerator().generate(messages: chat)
let expected = [
[
"role": "system",
"content": [
[
"type": "text",
"text": "You are a useful agent.",
]
],
],
[
"role": "user",
"content": [
[
"type": "text",
"text": "Tell me a story.",
]
],
],
]
assertEqual(expected, messages)
}
// MARK: - Mistral3 Message Generator Tests
public func testMistral3ConversionText() {
let chat: [Chat.Message] = [
.system("You are a useful agent."),
.user("Tell me a story."),
]
let messages = Mistral3MessageGenerator().generate(messages: chat)
let expected: [[String: any Sendable]] = [
[
"role": "system",
"content": [
[
"type": "text",
"text": "You are a useful agent.",
]
],
],
[
"role": "user",
"content": [
[
"type": "text",
"text": "Tell me a story.",
]
],
],
]
assertEqual(expected, messages)
}
public func testMistral3ConversionWithImage() {
let chat: [Chat.Message] = [
.user(
"What is this?",
images: [
.url(
URL(
string: "https://opensource.apple.com/images/projects/mlx.f5c59d8b.png")!
)
])
]
let messages = Mistral3MessageGenerator().generate(messages: chat)
let expected: [[String: any Sendable]] = [
[
"role": "user",
"content": [
[
"type": "image"
],
[
"type": "text",
"text": "What is this?",
],
],
]
]
assertEqual(expected, messages)
}
public func testMistral3ConversionToolRole() {
let chat: [Chat.Message] = [
.tool("The weather is sunny, 14°C.")
]
let messages = Mistral3MessageGenerator().generate(messages: chat)
let expected: [[String: any Sendable]] = [
[
"role": "tool",
"content": [
[
"type": "text",
"text": "The weather is sunny, 14°C.",
]
],
]
]
assertEqual(expected, messages)
}
// MARK: - Qwen2 Message Generator Tests
public func testQwen2ConversionImage() {
let chat: [Chat.Message] = [
.system("You are a useful agent."),
.user(
"What is this?",
images: [
.url(
URL(
string: "https://opensource.apple.com/images/projects/mlx.f5c59d8b.png")!
)
]),
]
let messages = Qwen2VLMessageGenerator().generate(messages: chat)
let expected = [
[
"role": "system",
"content": [
[
"type": "text",
"text": "You are a useful agent.",
]
],
],
[
"role": "user",
"content": [
[
"type": "text",
"text": "What is this?",
],
[
"type": "image"
],
],
],
]
assertEqual(expected, messages)
let userInput = UserInput(chat: chat)
XCTAssertEqual(userInput.images.count, 1)
}
}