package core_test import ( "os" "path/filepath" "strings" "testing" "amadan.net/oficina/slides/internal/slides/core" ) // TestCheckPassesWhatTheOpsWrite: a document the core's own ops built // is within the §2.6 vocabulary, and Check says so with nil. func TestCheckPassesWhatTheOpsWrite(t *testing.T) { ctx, rt := newRuntime(t) h := newDoc(t, ctx, rt, "check-ops", 1) if _, err := h.Ops(ctx, []byte(addSlide)); err != nil { t.Fatalf("Ops: %v", err) } if err := h.Check(ctx); err != nil { t.Errorf("Check on an ops-built document: %v", err) } // And on an empty one. empty := newDoc(t, ctx, rt, "check-empty", 1) if err := empty.Check(ctx); err != nil { t.Errorf("Check on an empty document: %v", err) } } // TestCheckRefusesAnUnknownMark: the update fixtures/poison.mjs writes // with a run under `unknown_mark` applies cleanly — the CRDT has no // opinion — and Check comes back as a RejectedError naming the block // and the attribute, while the view still reads the words. That gap is // the whole of codex 3. func TestCheckRefusesAnUnknownMark(t *testing.T) { ctx, rt := newRuntime(t) update, err := os.ReadFile(filepath.Join("..", "..", "slidestest", "testdata", "poison", "unknownmark.yjs")) if err != nil { t.Fatalf("read the unknownmark poison update (run node fixtures/poison.mjs): %v", err) } h := newDoc(t, ctx, rt, "check-poison", 1) if err := h.Apply(ctx, update); err != nil { t.Fatalf("Apply: %v", err) } view, err := h.JSON(ctx) if err != nil { t.Fatalf("JSON: %v", err) } if !strings.Contains(string(view), `"keep these words"`) { t.Errorf("the view lost the words the projection is supposed to tolerate: %s", view) } err = h.Check(ctx) if err == nil { t.Fatal("Check accepted a run under an unknown formatting attribute") } if !core.Rejected(err) { t.Errorf("Check's finding is not a RejectedError: %T %v", err, err) } want := `slide "poisonmrksld" block "poisonmrkblk" text: paragraph 0 carries the formatting attribute "unknown_mark", which is not one of b, i, c, h, href` if err.Error() != want { t.Errorf("Check message:\n got %q\nwant %q", err.Error(), want) } // The check only reads: the handle is as usable as before. if _, err := h.Ops(ctx, []byte(addSlide)); err != nil { t.Errorf("Ops after a Check finding: %v", err) } } // TestVectorsPassTheCheck: every committed vector is a document the // wire would accept. fixtures/generate.mjs asserts the same through // check.mjs when it writes them, so this is the two implementations // agreeing on the fixtures they share. func TestVectorsPassTheCheck(t *testing.T) { ctx, rt := newRuntime(t) for _, name := range vectorNames(t) { t.Run(name, func(t *testing.T) { update, err := os.ReadFile(filepath.Join(vectorsDir, name+".yjs")) if err != nil { t.Fatalf("read update: %v", err) } h := newDoc(t, ctx, rt, name, 1) if err := h.Apply(ctx, update); err != nil { t.Fatalf("Apply: %v", err) } if err := h.Check(ctx); err != nil { t.Errorf("Check: %v", err) } }) } }