v0.4.0 — Phase β-3 Editor
Voller Editor-Flow für Decks und 5 Card-Types (basic, basic-reverse, cloze, typing, multiple-choice). image-occlusion + audio-front kommen mit β-4 (Media). Anki-Import bleibt vorerst aus (Web parsed client- side, gibt keinen Server-Import-Endpoint zu rufen). - DeckCreateBody/UpdateBody, CardCreateBody/UpdateBody Encodable mit snake_case-CodingKeys, nil-Felder werden weggelassen - CardFieldsBuilder mit Type-spezifischen Pflicht-Feld-Konstruktoren - CardsAPI: createDeck/updateDeck/deleteDeck + createCard/updateCard/deleteCard - DeckEditorView (Create + Edit in einer View): Color-Picker mit 8-Preset-Palette, Category-Picker (11 Kats, deutsche Labels), Visibility-Segmented-Control - CardEditorView mit Type-Picker und dynamischen Feldern je Typ. Cloze-Sektion zeigt Live-Cluster-Count und Hint-Syntax-Hinweis. image-occlusion/audio-front zeigen β-4-Placeholder - DeckDetailView mit Action-Buttons (Lernen, Karte hinzufügen, Bearbeiten, Löschen mit Confirmation) - DeckListView: "+"-Button im Toolbar (Leading) für Create-Sheet - 7 neue Encoding-Tests (24 Unit-Tests + 1 UI-Test grün) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3b861af3fb
commit
cf1160b270
9 changed files with 930 additions and 19 deletions
100
Tests/UnitTests/MutationEncodingTests.swift
Normal file
100
Tests/UnitTests/MutationEncodingTests.swift
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import Foundation
|
||||
import Testing
|
||||
@testable import CardsNative
|
||||
|
||||
@Suite("Mutation Body Encoding")
|
||||
struct MutationEncodingTests {
|
||||
private func encode<T: Encodable>(_ value: T) throws -> [String: Any] {
|
||||
let data = try JSONEncoder().encode(value)
|
||||
return try JSONSerialization.jsonObject(with: data) as! [String: Any]
|
||||
}
|
||||
|
||||
@Test("DeckCreateBody nutzt snake_case und lässt nil weg")
|
||||
func deckCreateBody() throws {
|
||||
let body = DeckCreateBody(
|
||||
name: "Spanisch",
|
||||
description: nil,
|
||||
color: "#10803D",
|
||||
category: .language,
|
||||
visibility: .private
|
||||
)
|
||||
let json = try encode(body)
|
||||
#expect(json["name"] as? String == "Spanisch")
|
||||
#expect(json["color"] as? String == "#10803D")
|
||||
#expect(json["category"] as? String == "language")
|
||||
#expect(json["visibility"] as? String == "private")
|
||||
// description war nil — sollte nicht im JSON sein
|
||||
#expect(json["description"] == nil)
|
||||
}
|
||||
|
||||
@Test("DeckUpdateBody kann archived: true setzen")
|
||||
func deckUpdateBodyArchived() throws {
|
||||
let body = DeckUpdateBody(archived: true)
|
||||
let json = try encode(body)
|
||||
#expect(json["archived"] as? Bool == true)
|
||||
#expect(json["name"] == nil)
|
||||
}
|
||||
|
||||
@Test("CardCreateBody für basic-Type")
|
||||
func cardCreateBodyBasic() throws {
|
||||
let body = CardCreateBody(
|
||||
deckId: "deck_1",
|
||||
type: .basic,
|
||||
fields: CardFieldsBuilder.basic(front: "Hallo", back: "Hello"),
|
||||
mediaRefs: nil
|
||||
)
|
||||
let json = try encode(body)
|
||||
#expect(json["deck_id"] as? String == "deck_1")
|
||||
#expect(json["type"] as? String == "basic")
|
||||
let fields = json["fields"] as? [String: String]
|
||||
#expect(fields?["front"] == "Hallo")
|
||||
#expect(fields?["back"] == "Hello")
|
||||
#expect(json["media_refs"] == nil)
|
||||
}
|
||||
|
||||
@Test("CardCreateBody für basic-reverse Type-Name")
|
||||
func cardCreateBodyBasicReverse() throws {
|
||||
let body = CardCreateBody(
|
||||
deckId: "d",
|
||||
type: .basicReverse,
|
||||
fields: CardFieldsBuilder.basic(front: "a", back: "b"),
|
||||
mediaRefs: nil
|
||||
)
|
||||
let json = try encode(body)
|
||||
#expect(json["type"] as? String == "basic-reverse")
|
||||
}
|
||||
|
||||
@Test("CardCreateBody für cloze")
|
||||
func cardCreateBodyCloze() throws {
|
||||
let body = CardCreateBody(
|
||||
deckId: "d",
|
||||
type: .cloze,
|
||||
fields: CardFieldsBuilder.cloze(text: "Die {{c1::Sonne}} scheint."),
|
||||
mediaRefs: nil
|
||||
)
|
||||
let json = try encode(body)
|
||||
#expect(json["type"] as? String == "cloze")
|
||||
let fields = json["fields"] as? [String: String]
|
||||
#expect(fields?["text"] == "Die {{c1::Sonne}} scheint.")
|
||||
}
|
||||
|
||||
@Test("CardCreateBody multiple-choice Type-Name")
|
||||
func cardCreateBodyMultipleChoice() throws {
|
||||
let body = CardCreateBody(
|
||||
deckId: "d",
|
||||
type: .multipleChoice,
|
||||
fields: CardFieldsBuilder.multipleChoice(front: "Q", answer: "A"),
|
||||
mediaRefs: nil
|
||||
)
|
||||
let json = try encode(body)
|
||||
#expect(json["type"] as? String == "multiple-choice")
|
||||
}
|
||||
|
||||
@Test("CardUpdateBody nur mit fields")
|
||||
func cardUpdateBodyFieldsOnly() throws {
|
||||
let body = CardUpdateBody(fields: ["front": "neu"], mediaRefs: nil)
|
||||
let json = try encode(body)
|
||||
#expect((json["fields"] as? [String: String])?["front"] == "neu")
|
||||
#expect(json["media_refs"] == nil)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue