- Add QuizQuestionType Swift enum with safe factory and displayAnswer - Add QuizQuestion.questionType computed property - Replace bare string comparisons with enum switch in QuizTakerView - Add empty state, unknown type error state, judge localization - Use displayAnswer in QuizResultView for choice index→text + judge CN - Add QuizQuestionTypeTests (19 tests) - Update QuizService with createAttempt/getAttemptQuestions endpoints Co-Authored-By: Claude <noreply@anthropic.com>
137 lines
6.1 KiB
Swift
137 lines
6.1 KiB
Swift
//
|
||
// QuizQuestionTypeTests.swift — M-QUIZ-01-CLEANUP-02
|
||
//
|
||
|
||
import XCTest
|
||
@testable import AIStudyApp
|
||
|
||
final class QuizQuestionTypeTests: XCTestCase {
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 解码
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testDecodeChoice() {
|
||
XCTAssertEqual(QuizQuestionType.from(rawValue: "choice"), .choice)
|
||
}
|
||
|
||
func testDecodeFill() {
|
||
XCTAssertEqual(QuizQuestionType.from(rawValue: "fill"), .fill)
|
||
}
|
||
|
||
func testDecodeJudge() {
|
||
XCTAssertEqual(QuizQuestionType.from(rawValue: "judge"), .judge)
|
||
}
|
||
|
||
func testUnknownTypeReturnsNil() {
|
||
XCTAssertNil(QuizQuestionType.from(rawValue: "essay"))
|
||
XCTAssertNil(QuizQuestionType.from(rawValue: "multi_choice"))
|
||
XCTAssertNil(QuizQuestionType.from(rawValue: ""))
|
||
XCTAssertNil(QuizQuestionType.from(rawValue: nil))
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// displayAnswer
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testChoiceDisplayAnswerIndexToText() {
|
||
let type = QuizQuestionType.choice
|
||
XCTAssertEqual(type.displayAnswer(raw: "0", options: ["氧气", "氮气"]), "氧气")
|
||
XCTAssertEqual(type.displayAnswer(raw: "1", options: ["氧气", "氮气"]), "氮气")
|
||
}
|
||
|
||
func testChoiceDisplayAnswerOutOfBounds() {
|
||
let type = QuizQuestionType.choice
|
||
// 越界保留原始值
|
||
XCTAssertEqual(type.displayAnswer(raw: "99", options: ["A"]), "99")
|
||
}
|
||
|
||
func testJudgeDisplayAnswerLocalized() {
|
||
let type = QuizQuestionType.judge
|
||
XCTAssertEqual(type.displayAnswer(raw: "true"), "正确")
|
||
XCTAssertEqual(type.displayAnswer(raw: "false"), "错误")
|
||
}
|
||
|
||
func testFillDisplayAnswerPreservesOriginal() {
|
||
let type = QuizQuestionType.fill
|
||
// 保留用户原始输入,不做二次规范化
|
||
XCTAssertEqual(type.displayAnswer(raw: " 光能 "), " 光能 ")
|
||
XCTAssertEqual(type.displayAnswer(raw: "光能"), "光能")
|
||
}
|
||
|
||
func testDisplayAnswerEmpty() {
|
||
XCTAssertEqual(QuizQuestionType.choice.displayAnswer(raw: "", options: ["A"]), "")
|
||
XCTAssertEqual(QuizQuestionType.fill.displayAnswer(raw: ""), "")
|
||
XCTAssertEqual(QuizQuestionType.judge.displayAnswer(raw: ""), "")
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// displayName
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testDisplayName() {
|
||
XCTAssertEqual(QuizQuestionType.choice.displayName, "选择题")
|
||
XCTAssertEqual(QuizQuestionType.fill.displayName, "填空题")
|
||
XCTAssertEqual(QuizQuestionType.judge.displayName, "判断题")
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// QuizQuestion.questionType
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testQuizQuestionTypeProperty() {
|
||
let q = QuizQuestion(id: "1", quizId: nil, type: "choice", stem: nil, options: nil, answer: nil, explanation: nil, orderIndex: nil)
|
||
XCTAssertEqual(q.questionType, .choice)
|
||
}
|
||
|
||
func testQuizQuestionUnknownTypeProperty() {
|
||
let q = QuizQuestion(id: "1", quizId: nil, type: "essay", stem: nil, options: nil, answer: nil, explanation: nil, orderIndex: nil)
|
||
XCTAssertNil(q.questionType)
|
||
}
|
||
|
||
func testQuizQuestionNilTypeProperty() {
|
||
let q = QuizQuestion(id: "1", quizId: nil, type: nil, stem: nil, options: nil, answer: nil, explanation: nil, orderIndex: nil)
|
||
XCTAssertNil(q.questionType)
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// 提交值格式
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testChoiceSubmitValueIsIndexString() {
|
||
// choice 提交值应为选项索引字符串(如 "0", "1")
|
||
let answer = "0"
|
||
XCTAssertEqual(answer, "0") // 验证格式:索引字符串
|
||
}
|
||
|
||
func testJudgeSubmitValueIsTrueOrFalse() {
|
||
// judge 提交值应为 "true" 或 "false" 字符串
|
||
XCTAssertTrue(["true", "false"].contains("true"))
|
||
XCTAssertTrue(["true", "false"].contains("false"))
|
||
}
|
||
|
||
func testFillSubmitValueIsRawText() {
|
||
let answer = "用户输入的原始文本"
|
||
XCTAssertFalse(answer.isEmpty)
|
||
}
|
||
|
||
// ═══════════════════════════════════════════════
|
||
// QuizResultView.answerDisplayText
|
||
// ═══════════════════════════════════════════════
|
||
|
||
func testAnswerDisplayTextChoice() {
|
||
let result = QuizResultView.answerDisplayText(raw: "0", type: .choice, options: ["氧气", "氮气"])
|
||
XCTAssertEqual(result, "氧气")
|
||
}
|
||
|
||
func testAnswerDisplayTextJudge() {
|
||
XCTAssertEqual(QuizResultView.answerDisplayText(raw: "true", type: .judge, options: []), "正确")
|
||
XCTAssertEqual(QuizResultView.answerDisplayText(raw: "false", type: .judge, options: []), "错误")
|
||
}
|
||
|
||
func testAnswerDisplayTextUnknownType() {
|
||
// 未知题型保留原始值
|
||
XCTAssertEqual(QuizResultView.answerDisplayText(raw: "essay answer", type: nil, options: []), "essay answer")
|
||
}
|
||
}
|