import Testing import Foundation @testable import 康康 struct ModelManifestTests { @Test func llmHasNineFunctionalFiles() { // 主模型已切 Gemma-3n E2B(text-only),9 个运行文件。 #expect(ModelManifest.files(for: .llm).count == 9) } @Test func vlHasFourteenFunctionalFiles() { #expect(ModelManifest.files(for: .vl).count == 14) } @Test func llmTotalBytesMatchesManifest() { // Gemma-3n-E2B-it-lm-4bit 全部运行文件字节之和(ModelScope repo/files 实测,2026-06)。 #expect(ModelManifest.totalBytes(for: .llm) == 2_547_095_782) } @Test func vlTotalBytesMatchesManifest() { #expect(ModelManifest.totalBytes(for: .vl) == 3_109_729_929) } @Test func mnnHasSixFunctionalFiles() { #expect(ModelManifest.files(for: .mnnLLM).count == 6) } @Test func mnnTotalBytesMatchesManifest() { #expect(ModelManifest.totalBytes(for: .mnnLLM) == 1_185_759_005) } @Test func mnnHasEssentialRuntimeFiles() { let names = ModelManifest.files(for: .mnnLLM).map(\.path) #expect(names.contains("config.json")) #expect(names.contains("llm.mnn")) #expect(names.contains("llm.mnn.weight")) #expect(names.contains("tokenizer.txt")) } @Test func mnnFileURLUsesRepoPath() { // .mnnLLM 已停用但仍配 ModelScope 源备查;fileURL 走 modelscope resolve/master。 let file = ModelFile(path: "config.json", bytes: 652) let url = ModelManifest.fileURL(for: .mnnLLM, file: file) #expect(url.absoluteString == "https://modelscope.cn/models/MNN/Qwen3.5-2B-MNN/resolve/master/config.json") } @Test func excludesReadmeAndGitattributes() { for kind in [ModelKind.llm, .vl] { let names = ModelManifest.files(for: kind).map(\.path) #expect(!names.contains("README.md")) #expect(!names.contains(".gitattributes")) } } @Test func includesEssentialFiles() { let llm = ModelManifest.files(for: .llm).map(\.path) #expect(llm.contains("config.json")) #expect(llm.contains("model.safetensors")) #expect(llm.contains("tokenizer.json")) let vl = ModelManifest.files(for: .vl).map(\.path) #expect(vl.contains("preprocessor_config.json")) // VL 拍照识别必需 #expect(vl.contains("model.safetensors")) } @Test func llmFileURLUsesModelScopeRepo() { // 主模型走 ModelScope 官方 resolve/master(大陆可达,302 跳 OSS 支持 Range 续传)。 let file = ModelFile(path: "config.json", bytes: 107_207) let url = ModelManifest.fileURL(for: .llm, file: file) #expect(url.absoluteString == "https://modelscope.cn/models/mlx-community/gemma-3n-E2B-it-lm-4bit/resolve/master/config.json") } }