197 lines
5.3 KiB
Go
197 lines
5.3 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", segmentWant, 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) {
|
|
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, segmentEarly) {
|
|
t.Errorf("Instantiated: %#v, want %#v", got, segmentEarly)
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|