nixbuild/instantiated_test.go

210 lines
6.0 KiB
Go

package nix_test
import (
"errors"
"io"
"os"
"os/exec"
"slices"
"strings"
"testing"
"gensokyo.uk/nix"
)
func TestInstantiated(t *testing.T) {
stubNixCommand(t)
testCases := []struct {
name string
want []string
wantErr error
}{
{"bad fields", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedBadFields}},
{"unexpected quotes left", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"unexpected quotes right", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"unexpected quotes short", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"not absolute", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedNotAbsolute}},
{"good segment", []string{
"/nix/store/3zilrlmq7r6rpzfd94mwss32b62yinj5-bootstrap-stage0-stdenv-linux.drv",
"/nix/store/7yfwy95p6lcdpljdajs5aw10h6q0sfx0-update-autotools-gnu-config-scripts-hook.drv",
"/nix/store/bamwxswxacs3cjdcydv0z7bj22d7g2kc-config.guess-948ae97.drv",
"/nix/store/gyks6vvl7x0gq214ldjhi3w4rg37nh8i-zlib-1.3.1.tar.gz.drv",
"/nix/store/nbsdqpfzh1jlpmh95s69b3iivfcvv3lh-config.sub-948ae97.drv",
"/nix/store/ysp83x9nrks28zkblqmnc1s1kb68dr69-gnu-config-2024-01-01.drv",
}, nil},
{"getchoo atlas", getchooAtlasInstantiated, nil},
{"getchoo glados", getchooGladosInstantiated, nil},
{"pluiedev pappardelle", pluiedevPappardelleInstantiated, nil},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var stderr io.Writer
if tc.wantErr != nil {
stderr = os.Stderr
}
sample := instSample[tc.name]
t.Run("decoder", func(t *testing.T) {
out := strings.NewReader(sample)
decoder := nix.NewInstantiatedDecoder(out, stderr)
got, err := decoder.Decode()
if !errors.Is(err, tc.wantErr) {
t.Fatalf("Decode: error = %v, want %v", err, tc.wantErr)
}
if tc.wantErr != nil {
t.Logf("Decode: error = %v", err)
t.Run("scan after error", func(t *testing.T) {
if decoder.Scan() {
t.Fatalf("Scan unexpectedly succeeded on faulted decoder")
}
})
return
}
if !slices.Equal(got, tc.want) {
t.Errorf("Decode: %#v, want %#v", got, tc.want)
}
})
t.Run("evaluator", func(t *testing.T) {
ctx := newStubContext(t.Context(), nil, os.Stdout, stderr)
got, err := nix.EvalInstantiated(ctx, tc.name)
if !errors.Is(err, tc.wantErr) {
t.Fatalf("EvalInstantiated: error = %v, want %v", err, tc.wantErr)
}
if tc.wantErr != nil {
t.Logf("EvalInstantiated: error = %v", err)
return
}
if !slices.Equal(got, tc.want) {
t.Errorf("EvalInstantiated: %#v, want %#v", got, tc.want)
}
})
})
}
}
func stubInstantiatedEvaluator(args []string) error {
_, _ = os.Stderr.Write([]byte(instSample[args[0]]))
return nil
}
func TestInstantiatedDecoderStopEarly(t *testing.T) {
want := []string{
"/nix/store/gyks6vvl7x0gq214ldjhi3w4rg37nh8i-zlib-1.3.1.tar.gz.drv",
"/nix/store/bamwxswxacs3cjdcydv0z7bj22d7g2kc-config.guess-948ae97.drv",
"/nix/store/nbsdqpfzh1jlpmh95s69b3iivfcvv3lh-config.sub-948ae97.drv",
}
decoder := nix.NewInstantiatedDecoder(strings.NewReader(segmentPrefix+segmentBody+segmentSuffix), os.Stderr)
counter := 3
got := make([]string, 0, counter)
for drv := range decoder.Instantiated() {
got = append(got, drv)
counter--
if counter == 0 {
break
}
}
if !slices.Equal(got, want) {
t.Errorf("Instantiated: %#v, want %#v", got, want)
}
}
func TestInstantiatedEvaluatorBadCommand(t *testing.T) {
wantErr := os.ErrNotExist
breakNixCommand(t)
if _, err := nix.EvalInstantiated(
nix.New(t.Context(), nil, os.Stdout, os.Stderr),
"",
); !errors.Is(err, wantErr) {
t.Errorf("EvalInstantiated: error = %v, want %v", err, wantErr)
}
}
func TestInstantiatedEvaluatorAlreadySet(t *testing.T) {
stubNixCommand(t)
if _, err := nix.EvalInstantiated(
newStubContextCommand(func(cmd *exec.Cmd) { cmd.Stderr = os.Stderr }, t.Context(), nil, os.Stdout, os.Stderr),
"",
); err == nil {
t.Errorf("EvalInstantiated unexpectedly succeeded")
}
}
func TestMalformedInstantiatedError(t *testing.T) {
t.Run("bad type", func(t *testing.T) {
badErr := errors.New("")
if errors.Is(new(nix.MalformedInstantiatedError), badErr) {
t.Error("unexpected MalformedInstantiatedError equivalence")
}
})
t.Run("nil", func(t *testing.T) {
if errors.Is(new(nix.MalformedInstantiatedError), (*nix.MalformedInstantiatedError)(nil)) {
t.Error("unexpected MalformedInstantiatedError equivalence")
}
})
t.Run("unreachable", func(t *testing.T) {
defer func() {
wantPanic := "unreachable"
if r := recover(); r != wantPanic {
t.Errorf("Error: panic = %q, want %q", r, wantPanic)
}
}()
_ = (&nix.MalformedInstantiatedError{Type: -1}).Error()
})
}
func benchmarkInstantiatedDecoder(b *testing.B, out string) {
decoder := nix.NewInstantiatedDecoder(strings.NewReader(out), nil)
for b.Loop() {
retry:
if !decoder.Scan() {
b.StopTimer()
if err := decoder.Err(); err != nil {
b.Fatalf("Decode: error = %v", err)
}
decoder = nix.NewInstantiatedDecoder(strings.NewReader(out), nil)
b.StartTimer()
goto retry
}
b.StopTimer()
if !strings.HasPrefix(decoder.Text(), "/nix/store") {
b.Fatalf("Text: unexpected prefix: %s", decoder.Text())
}
b.StartTimer()
}
}
func BenchmarkInstantiatedDecoder(b *testing.B) {
benchmarkInstantiatedDecoder(b, pluiedevPappardelleOut)
}
func benchmarkInstantiated(b *testing.B, out string, want []string) {
for b.Loop() {
v, _ := nix.NewInstantiatedDecoder(strings.NewReader(out), nil).Decode()
b.StopTimer()
if !slices.Equal(v, want) {
b.Fatalf("Decode: %#v, want %#v", v, want)
}
b.StartTimer()
}
}
func BenchmarkInstantiated(b *testing.B) {
/* 27750 raw, 10729 deduplicated */
benchmarkInstantiated(b, getchooGladosOut, getchooGladosInstantiated)
}
func BenchmarkInstantiatedCopy(b *testing.B) {
/* 40177 raw, 10685 deduplicated */
benchmarkInstantiated(b, pluiedevPappardelleOut, pluiedevPappardelleInstantiated)
}