diff --git a/internal/shutils/decoder/decoder_test.go b/internal/shutils/decoder/decoder_test.go new file mode 100644 index 0000000..1fbcc75 --- /dev/null +++ b/internal/shutils/decoder/decoder_test.go @@ -0,0 +1,206 @@ +package decoder_test + +import ( + "bytes" + "context" + "errors" + "os" + "reflect" + "strings" + "testing" + + "go.arsenm.dev/lure/distro" + "go.arsenm.dev/lure/internal/shutils/decoder" + "mvdan.cc/sh/v3/interp" + "mvdan.cc/sh/v3/syntax" +) + +type BuildVars struct { + Name string `sh:"name,required"` + Version string `sh:"version,required"` + Release int `sh:"release,required"` + Epoch uint `sh:"epoch"` + Description string `sh:"desc"` + Homepage string `sh:"homepage"` + Maintainer string `sh:"maintainer"` + Architectures []string `sh:"architectures"` + Licenses []string `sh:"license"` + Provides []string `sh:"provides"` + Conflicts []string `sh:"conflicts"` + Depends []string `sh:"deps"` + BuildDepends []string `sh:"build_deps"` + Replaces []string `sh:"replaces"` +} + +const testScript = ` + name='test' + version='0.0.1' + release=1 + epoch=2 + desc="Test package" + homepage='https://lure.arsenm.dev' + maintainer='Arsen Musayelyan ' + architectures=('arm64' 'amd64') + license=('GPL-3.0-or-later') + provides=('test') + conflicts=('test') + replaces=('test-old') + replaces_test_os=('test-legacy') + + deps=('sudo') + + build_deps=('golang') + build_deps_arch=('go') + + test() { + echo "Test" + } + + package() { + install-binary test + } +` + +var osRelease = &distro.OSRelease{ + ID: "test_os", + Like: []string{"arch"}, +} + +func TestDecodeVars(t *testing.T) { + ctx := context.Background() + + fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "lure.sh") + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + runner, err := interp.New() + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + err = runner.Run(ctx, fl) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + dec := decoder.New(osRelease, runner) + + var bv BuildVars + err = dec.DecodeVars(&bv) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + expected := BuildVars{ + Name: "test", + Version: "0.0.1", + Release: 1, + Epoch: 2, + Description: "Test package", + Homepage: "https://lure.arsenm.dev", + Maintainer: "Arsen Musayelyan ", + Architectures: []string{"arm64", "amd64"}, + Licenses: []string{"GPL-3.0-or-later"}, + Provides: []string{"test"}, + Conflicts: []string{"test"}, + Replaces: []string{"test-legacy"}, + Depends: []string{"sudo"}, + BuildDepends: []string{"go"}, + } + + if !reflect.DeepEqual(bv, expected) { + t.Errorf("Expected %v, got %v", expected, bv) + } +} + +func TestDecodeVarsMissing(t *testing.T) { + ctx := context.Background() + + const testScript = ` + name='test' + epoch=2 + desc="Test package" + homepage='https://lure.arsenm.dev' + maintainer='Arsen Musayelyan ' + architectures=('arm64' 'amd64') + license=('GPL-3.0-or-later') + provides=('test') + conflicts=('test') + replaces=('test-old') + replaces_test_os=('test-legacy') + + deps=('sudo') + + build_deps=('golang') + build_deps_arch=('go') + + test() { + echo "Test" + } + + package() { + install-binary test + } + ` + + fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "lure.sh") + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + runner, err := interp.New() + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + err = runner.Run(ctx, fl) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + dec := decoder.New(osRelease, runner) + + var bv BuildVars + err = dec.DecodeVars(&bv) + + var notFoundErr decoder.VarNotFoundError + if !errors.As(err, ¬FoundErr) { + t.Fatalf("Expected VarNotFoundError, got %T %v", err, err) + } +} + +func TestGetFunc(t *testing.T) { + ctx := context.Background() + + fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "lure.sh") + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + runner, err := interp.New() + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + err = runner.Run(ctx, fl) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + dec := decoder.New(osRelease, runner) + fn, ok := dec.GetFunc("test") + if !ok { + t.Fatalf("Expected test() function to exist") + } + + buf := &bytes.Buffer{} + err = fn(ctx, interp.StdIO(os.Stdin, buf, buf)) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + if buf.String() != "Test\n" { + t.Fatalf(`Expected "Test\n", got %#v`, buf.String()) + } +} diff --git a/internal/shutils/exec_test.go b/internal/shutils/exec_test.go new file mode 100644 index 0000000..e7597b2 --- /dev/null +++ b/internal/shutils/exec_test.go @@ -0,0 +1,106 @@ +package shutils_test + +import ( + "context" + "strings" + "testing" + + "go.arsenm.dev/lure/distro" + "go.arsenm.dev/lure/internal/shutils" + "go.arsenm.dev/lure/internal/shutils/decoder" + "mvdan.cc/sh/v3/interp" + "mvdan.cc/sh/v3/syntax" +) + +const testScript = ` + name='test' + version='0.0.1' + release=1 + epoch=2 + desc="Test package" + homepage='https://lure.arsenm.dev' + maintainer='Arsen Musayelyan ' + architectures=('arm64' 'amd64') + license=('GPL-3.0-or-later') + provides=('test') + conflicts=('test') + replaces=('test-old') + replaces_test_os=('test-legacy') + + deps=('sudo') + + build_deps=('golang') + build_deps_arch=('go') + + test() { + test-cmd "Hello, World" + test-fb + } + + package() { + install-binary test + } +` + +var osRelease = &distro.OSRelease{ + ID: "test_os", + Like: []string{"arch"}, +} + +func TestExecFuncs(t *testing.T) { + ctx := context.Background() + + fl, err := syntax.NewParser().Parse(strings.NewReader(testScript), "lure.sh") + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + runner, err := interp.New() + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + err = runner.Run(ctx, fl) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + dec := decoder.New(osRelease, runner) + fn, ok := dec.GetFunc("test") + if !ok { + t.Fatalf("Expected test() function to exist") + } + + eh := shutils.ExecFuncs{ + "test-cmd": func(hc interp.HandlerContext, name string, args []string) error { + if name != "test-cmd" { + t.Errorf("Expected name to be 'test-cmd', got '%s'", name) + } + + if len(args) < 1 { + t.Fatalf("Expected at least one argument, got %d", len(args)) + } + + if args[0] != "Hello, World" { + t.Errorf("Expected first argument to be 'Hello, World', got '%s'", args[0]) + } + + return nil + }, + } + + fbInvoked := false + fbHandler := func(context.Context, []string) error { + fbInvoked = true + return nil + } + + err = fn(ctx, interp.ExecHandler(eh.ExecHandler(fbHandler))) + if err != nil { + t.Errorf("Expected no error, got %s", err) + } + + if !fbInvoked { + t.Errorf("Expected fallback handler to be invoked") + } +} diff --git a/internal/shutils/nop_test.go b/internal/shutils/nop_test.go new file mode 100644 index 0000000..bcea3cf --- /dev/null +++ b/internal/shutils/nop_test.go @@ -0,0 +1,40 @@ +package shutils_test + +import ( + "bytes" + "context" + "os" + "strings" + "testing" + + "go.arsenm.dev/lure/internal/shutils" + "mvdan.cc/sh/v3/interp" + "mvdan.cc/sh/v3/syntax" +) + +func TestNopExec(t *testing.T) { + ctx := context.Background() + + fl, err := syntax.NewParser().Parse(strings.NewReader(`/bin/echo test`), "lure.sh") + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + buf := &bytes.Buffer{} + runner, err := interp.New( + interp.ExecHandler(shutils.NopExec), + interp.StdIO(os.Stdin, buf, buf), + ) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + err = runner.Run(ctx, fl) + if err != nil { + t.Fatalf("Expected no error, got %s", err) + } + + if buf.String() != "" { + t.Fatalf("Expected empty string, got %#v", buf.String()) + } +}