// SPDX-License-Identifier: MIT
// Copyright (c) 2023 Robin Jarry

package opt_test

import (
	"testing"

	"git.sr.ht/~rjarry/go-opt/v2"
	"github.com/stretchr/testify/assert"
)

func TestLexArgs(t *testing.T) {
	vectors := []struct {
		cmd             string
		args            []string
		lead            string
		trail           string
		shift           int
		shifted         []string
		shiftArgs       []string
		shiftString     string
		shiftLead       string
		shiftTrail      string
		prepend         string
		prependedArgs   []string
		prependedString string
		prependedLead   string
		prependedTrail  string
		cut             int
		cutted          []string
		cutArgs         []string
		cutString       string
		cutLead         string
		cutTrail        string
		extend          string
		extendedArgs    []string
		extendedString  string
		extendLead      string
		extendTrail     string
	}{
		{
			cmd:             "a b c",
			args:            []string{"a", "b", "c"},
			shift:           0,
			shifted:         []string{},
			shiftArgs:       []string{"a", "b", "c"},
			shiftString:     "a b c",
			prepend:         "z ",
			prependedArgs:   []string{"z", "a", "b", "c"},
			prependedString: "z a b c",
			cut:             0,
			cutted:          []string{},
			cutArgs:         []string{"z", "a", "b", "c"},
			cutString:       "z a b c",
			extend:          " x",
			extendedArgs:    []string{"z", "a", "b", "c", "x"},
			extendedString:  "z a b c x",
		},
		{
			cmd:             "   'foo'\t-bar c $d |   zz $bar 'x y z' ",
			args:            []string{"foo", "-bar", "c", "$d", "|", "zz", "$bar", "x y z"},
			lead:            "   ",
			trail:           " ",
			shift:           2,
			shifted:         []string{"foo", "-bar"},
			shiftArgs:       []string{"c", "$d", "|", "zz", "$bar", "x y z"},
			shiftString:     "c $d |   zz $bar 'x y z' ",
			shiftTrail:      " ",
			prepend:         `baz -p "$aeiouy noooo"`,
			prependedArgs:   []string{"baz", "-p", "$aeiouy noooo", "c", "$d", "|", "zz", "$bar", "x y z"},
			prependedString: `baz -p "$aeiouy noooo" c $d |   zz $bar 'x y z' `,
			prependedLead:   "",
			prependedTrail:  " ",
			cut:             1,
			cutted:          []string{"x y z"},
			cutArgs:         []string{"baz", "-p", "$aeiouy noooo", "c", "$d", "|", "zz", "$bar"},
			cutString:       `baz -p "$aeiouy noooo" c $d |   zz $bar`,
			extend:          "'eeeee eeee ",
			extendedArgs:    []string{"baz", "-p", "$aeiouy noooo", "c", "$d", "|", "zz", "$bar", "eeeee eeee "},
			extendedString:  `baz -p "$aeiouy noooo" c $d |   zz $bar 'eeeee eeee `,
			extendTrail:     "",
		},
		{
			cmd:             `foo -xz \"bar 'baz\"' "\$baz \" ok"`,
			args:            []string{"foo", "-xz", `"bar`, `baz\"`, `$baz " ok`},
			shift:           2,
			shifted:         []string{"foo", "-xz"},
			shiftArgs:       []string{`"bar`, `baz\"`, `$baz " ok`},
			shiftString:     `\"bar 'baz\"' "\$baz \" ok"`,
			prepend:         "find 'bleh' | xargs -uuuuu u",
			prependedArgs:   []string{"find", "bleh", "|", "xargs", "-uuuuu", "u", `"bar`, `baz\"`, `$baz " ok`},
			prependedString: `find 'bleh' | xargs -uuuuu u \"bar 'baz\"' "\$baz \" ok"`,
			cut:             2,
			cutted:          []string{`baz\"`, `$baz " ok`},
			cutArgs:         []string{"find", "bleh", "|", "xargs", "-uuuuu", "u", `"bar`},
			cutString:       `find 'bleh' | xargs -uuuuu u \"bar`,
			extend:          "|| rm -rf / &",
			extendedArgs:    []string{"find", "bleh", "|", "xargs", "-uuuuu", "u", `"bar`, "||", "rm", "-rf", "/", "&"},
			extendedString:  `find 'bleh' | xargs -uuuuu u \"bar || rm -rf / &`,
		},
	}
	for _, vec := range vectors {
		t.Run(vec.cmd, func(t *testing.T) {
			cmd := opt.LexArgs(vec.cmd)
			assert.Equal(t, vec.args, cmd.Args(), "args")
			assert.Equal(t, vec.lead, cmd.LeadingSpace(), "LeadingSpace")
			assert.Equal(t, vec.trail, cmd.TrailingSpace(), "TrailingSpace")
			shifted := cmd.Shift(vec.shift)
			assert.Equal(t, vec.shifted, shifted, "Shift")
			assert.Equal(t, vec.shiftArgs, cmd.Args(), "shifted.Args")
			assert.Equal(t, vec.shiftString, cmd.String(), "shifted.String")
			assert.Equal(t, vec.shiftLead, cmd.LeadingSpace(), "shifted.LeadingSpace")
			assert.Equal(t, vec.shiftTrail, cmd.TrailingSpace(), "shifted.TrailingSpace")
			cmd.Prepend(vec.prepend)
			assert.Equal(t, vec.prependedArgs, cmd.Args(), "prepended.Args")
			assert.Equal(t, vec.prependedString, cmd.String(), "prepended.String")
			assert.Equal(t, vec.prependedLead, cmd.LeadingSpace(), "prepended.LeadingSpace")
			assert.Equal(t, vec.prependedTrail, cmd.TrailingSpace(), "prepended.TrailingSpace")
			cutted := cmd.Cut(vec.cut)
			assert.Equal(t, vec.cutted, cutted, "Cut")
			assert.Equal(t, vec.cutArgs, cmd.Args(), "cut.Args")
			assert.Equal(t, vec.cutString, cmd.String(), "cut.String")
			assert.Equal(t, vec.cutLead, cmd.LeadingSpace(), "cut.LeadingSpace")
			assert.Equal(t, vec.cutTrail, cmd.TrailingSpace(), "cut.TrailingSpace")
			cmd.Extend(vec.extend)
			assert.Equal(t, vec.extendedArgs, cmd.Args(), "extend.Args")
			assert.Equal(t, vec.extendedString, cmd.String(), "extend.String")
			assert.Equal(t, vec.extendLead, cmd.LeadingSpace(), "extend.LeadingSpace")
			assert.Equal(t, vec.extendTrail, cmd.TrailingSpace(), "extend.TrailingSpace")
		})
	}
}
