package capsule_test import ( "bytes" "context" "testing" "g.activething.com/go/DateKeys/capsule" "g.activething.com/go/DateKeys/extension" "g.activething.com/go/DateKeys/internal/testkit" ) const mutationsFile = "../testdata/vectors/mutations.json" // build returns a capsule made by testkit.Build and the options to open it. func build(t *testing.T, b testkit.Build) ([]byte, capsule.OpenOptions) { t.Helper() if b.Plaintext == nil { b.Plaintext = []byte("malicious creator") } out, err := b.Make() if err != nil { t.Fatal(err) } return out.DKC, capsule.OpenOptions{Registry: testkit.Registry(), Source: testkit.NewSource(testkit.Release(1000)), Now: testkit.Fixed(testkit.Genesis().AddDate(1, 0, 0))} } // Spec §64: every mutation of the corpus (testkit.Mutations), built afresh, // fails with its exact normative error at its exact step, or opens with its // verdicts, and a failure before the release request causes no request. The // thirty-three mutations of the first two lists of spec §64 are there once // for each format, and those of the lists of formats 2 and 3 once. func TestMutationCorpus(t *testing.T) { e, err := testkit.NewMutationEnv(fixtureDir) if err != nil { t.Fatal(err) } n := 0 for _, m := range testkit.Mutations() { if m.Spec { n++ } t.Run(m.Name, func(t *testing.T) { in, err := m.Make(e) if err != nil { t.Fatal(err) } if err := m.Check(in); err != nil { t.Fatal(err) } }) } if want := 3*testkit.SpecMutationsPerFormat + testkit.Format2SpecMutations + testkit.Format3SpecMutations + testkit.V011SpecMutations; n != want { t.Fatalf("spec §64 gives %d mutations, the corpus has %d", want, n) } } // The exported corpus, testdata/vectors/mutations.json, holds every mutation // of the corpus in order, and replaying each case from the file alone gives // exactly the recorded error and step. The capsules that are not built with // randomness are the ones the corpus derives from the fixtures. func TestExportedMutationCorpus(t *testing.T) { var f testkit.MutationFile if err := testkit.ReadJSON(mutationsFile, &f); err != nil { t.Fatal(err) } e, err := testkit.NewMutationEnv(fixtureDir) if err != nil { t.Fatal(err) } muts := testkit.Mutations() if len(f.Cases) != len(muts) { t.Fatalf("%d exported cases, the corpus has %d mutations", len(f.Cases), len(muts)) } for i, c := range f.Cases { m := muts[i] t.Run(c.Name, func(t *testing.T) { if c.Name != m.Name || c.Spec != m.Spec || c.Error != m.Code() || c.Step != m.Step || c.Network != m.Network || c.Frozen != m.Random || (c.Verdicts != nil) != (m.Verdicts != nil) { t.Fatalf("exported case %+v does not match mutation %q", c, m.Name) } if err := c.Check(fixtureDir); err != nil { t.Fatal(err) } if m.Random { if c.DKC.Base != "" { t.Fatal("a frozen capsule must not depend on a fixture") } return } want, err := m.Make(e) if err != nil { t.Fatal(err) } got, err := c.Input(fixtureDir) if err != nil { t.Fatal(err) } if !bytes.Equal(got.DKC, want.DKC) || !bytes.Equal(got.DKK, want.DKK) || got.NetworkSource != want.NetworkSource { t.Fatal("the exported capsule or .dkk differs from the one the mutation derives") } }) } } // Known critical extensions are accepted when the application declares them. func TestKnownCriticalExtensions(t *testing.T) { crit := []extension.Extension{{ID: "org.example.must-understand", Version: 1}} for _, b := range []testkit.Build{{HeaderCritical: crit}, {ControlCritical: crit}} { dkc, o := build(t, b) o.Extensions = extension.Set{"org.example.must-understand": {1}} var out bytes.Buffer if _, err := capsule.Open(context.Background(), &out, bytes.NewReader(dkc), o); err != nil || out.String() != "malicious creator" { t.Fatalf("known critical extension rejected: %v", err) } } }