more refactoring, fixed bug in shell mode output, fixed default

Separator and fixed #3
This commit is contained in:
2022-10-05 14:31:01 +02:00
parent 26e50cf908
commit 85277bbf5e
9 changed files with 186 additions and 96 deletions

View File

@@ -19,25 +19,26 @@ package lib
var (
// command line flags
Debug bool
XtendedOut bool
NoNumbering bool
ShowVersion bool
Columns string
UseColumns []int
Separator string = `(\s\s+|\t)`
OutflagExtended bool
OutflagMarkdown bool
OutflagOrgtable bool
OutflagShell bool
OutputMode string
InvertMatch bool
Debug bool
XtendedOut bool
NoNumbering bool
ShowVersion bool
Columns string
UseColumns []int
DefaultSeparator string = `(\s\s+|\t)`
Separator string = `(\s\s+|\t)`
OutflagExtended bool
OutflagMarkdown bool
OutflagOrgtable bool
OutflagShell bool
OutputMode string
InvertMatch bool
// used for validation
validOutputmodes = "(orgtbl|markdown|extended|ascii)"
// main program version
Version = "v1.0.5"
Version = "v1.0.6"
// generated version string, used by -v contains lib.Version on
// main branch, and lib.Version-$branch-$lastcommit-$date on

View File

@@ -48,8 +48,49 @@ func PrepareColumns() error {
return nil
}
func numberizeHeaders(data *Tabdata) {
// prepare headers: add numbers to headers
numberedHeaders := []string{}
for i, head := range data.headers {
if len(Columns) > 0 {
// -c specified
if !contains(UseColumns, i+1) {
// ignore this one
continue
}
}
if NoNumbering {
numberedHeaders = append(numberedHeaders, head)
} else {
numberedHeaders = append(numberedHeaders, fmt.Sprintf("%s(%d)", head, i+1))
}
}
data.headers = numberedHeaders
}
func reduceColumns(data *Tabdata) {
// exclude columns, if any
if len(Columns) > 0 {
reducedEntries := [][]string{}
reducedEntry := []string{}
for _, entry := range data.entries {
reducedEntry = nil
for i, value := range entry {
if !contains(UseColumns, i+1) {
continue
}
reducedEntry = append(reducedEntry, value)
}
reducedEntries = append(reducedEntries, reducedEntry)
}
data.entries = reducedEntries
}
}
func PrepareModeFlags() error {
if len(OutputMode) == 0 {
// associate short flags like -X with mode selector
switch {
case OutflagExtended:
OutputMode = "extended"

View File

@@ -52,6 +52,7 @@ func TestPrepareColumns(t *testing.T) {
}{
{"1,2,3", []int{1, 2, 3}, false},
{"1,2,", []int{}, true},
{"a,b", []int{}, true},
}
for _, tt := range tests {
@@ -71,3 +72,46 @@ func TestPrepareColumns(t *testing.T) {
})
}
}
func TestReduceColumns(t *testing.T) {
var tests = []struct {
expect [][]string
columns []int
}{
{
expect: [][]string{[]string{"a", "b"}},
columns: []int{1, 2},
},
{
expect: [][]string{[]string{"a", "c"}},
columns: []int{1, 3},
},
{
expect: [][]string{[]string{"a"}},
columns: []int{1},
},
{
expect: [][]string{nil},
columns: []int{4},
},
}
input := [][]string{[]string{"a", "b", "c"}}
Columns = "y" // used as a flag with len(Columns)...
for _, tt := range tests {
testname := fmt.Sprintf("reduce-columns-by-%+v", tt.columns)
t.Run(testname, func(t *testing.T) {
UseColumns = tt.columns
data := Tabdata{entries: input}
reduceColumns(&data)
if !reflect.DeepEqual(data.entries, tt.expect) {
t.Errorf("reduceColumns returned invalid data:\ngot: %+v\nexp: %+v", data.entries, tt.expect)
}
})
}
Columns = "" // reset for other tests
UseColumns = nil
}

View File

@@ -46,7 +46,6 @@ func parseFile(input io.Reader, pattern string) (Tabdata, error) {
hadFirst := false
separate := regexp.MustCompile(Separator)
patternR, err := regexp.Compile(pattern)
if err != nil {
return data, errors.Unwrap(fmt.Errorf("Regexp pattern %s is invalid: %w", pattern, err))

View File

@@ -28,26 +28,18 @@ func TestParser(t *testing.T) {
data := Tabdata{
maxwidthHeader: 5,
maxwidthPerCol: []int{
5,
5,
8,
5, 5, 8,
},
columns: 3,
headers: []string{
"ONE",
"TWO",
"THREE",
"ONE", "TWO", "THREE",
},
entries: [][]string{
[]string{
"asd",
"igig",
"cxxxncnc",
"asd", "igig", "cxxxncnc",
},
[]string{
"19191",
"EDD 1",
"X",
"19191", "EDD 1", "X",
},
},
}
@@ -58,6 +50,7 @@ asd igig cxxxncnc
readFd := strings.NewReader(table)
gotdata, err := parseFile(readFd, "")
Separator = DefaultSeparator
if err != nil {
t.Errorf("Parser returned error: %s\nData processed so far: %+v", err, gotdata)
@@ -77,9 +70,7 @@ func TestParserPatternmatching(t *testing.T) {
{
entries: [][]string{
[]string{
"asd",
"igig",
"cxxxncnc",
"asd", "igig", "cxxxncnc",
},
},
pattern: "ig",
@@ -88,9 +79,7 @@ func TestParserPatternmatching(t *testing.T) {
{
entries: [][]string{
[]string{
"19191",
"EDD 1",
"X",
"19191", "EDD 1", "X",
},
},
pattern: "ig",

View File

@@ -26,41 +26,10 @@ import (
)
func printData(data *Tabdata) {
// prepare headers: add numbers to headers
numberedHeaders := []string{}
for i, head := range data.headers {
if len(Columns) > 0 {
// -c specified
if !contains(UseColumns, i+1) {
// ignore this one
continue
}
}
if NoNumbering {
numberedHeaders = append(numberedHeaders, head)
} else {
numberedHeaders = append(numberedHeaders, fmt.Sprintf("%s(%d)", head, i+1))
}
}
data.headers = numberedHeaders
// prepare data
if len(Columns) > 0 {
reducedEntries := [][]string{}
reducedEntry := []string{}
for _, entry := range data.entries {
reducedEntry = nil
for i, value := range entry {
if !contains(UseColumns, i+1) {
continue
}
reducedEntry = append(reducedEntry, value)
}
reducedEntries = append(reducedEntries, reducedEntry)
}
data.entries = reducedEntries
if OutputMode != "shell" {
numberizeHeaders(data)
}
reduceColumns(data)
switch OutputMode {
case "extended":
@@ -190,6 +159,7 @@ func printShellData(data *Tabdata) {
var idx int
for _, entry := range data.entries {
idx = 0
shentries := []string{}
for i, value := range entry {
if len(Columns) > 0 {
if !contains(UseColumns, i+1) {
@@ -197,10 +167,10 @@ func printShellData(data *Tabdata) {
}
}
fmt.Printf("%s=\"%s\" ", data.headers[idx], value)
shentries = append(shentries, fmt.Sprintf("%s=\"%s\"", data.headers[idx], value))
idx++
}
fmt.Println()
fmt.Println(strings.Join(shentries, " "))
}
}
}

View File

@@ -18,15 +18,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package lib
import (
"fmt"
"os"
"strings"
"testing"
)
func TestPrinter(t *testing.T) {
table := `ONE TWO THREE
asd igig cxxxncnc
19191 EDD 1 X`
startdata := Tabdata{
maxwidthHeader: 5,
maxwidthPerCol: []int{
5,
5,
8,
},
columns: 3,
headers: []string{
"ONE", "TWO", "THREE",
},
entries: [][]string{
[]string{
"asd", "igig", "cxxxncnc",
},
[]string{
"19191", "EDD 1", "X",
},
},
}
expects := map[string]string{
"ascii": `ONE(1) TWO(2) THREE(3)
@@ -42,6 +60,8 @@ asd igig cxxxncnc
|--------|--------|----------|
| asd | igig | cxxxncnc |
| 19191 | EDD 1 | X |`,
"shell": `ONE="asd" TWO="igig" THREE="cxxxncnc"
ONE="19191" TWO="EDD 1" THREE="X"`,
}
r, w, err := os.Pipe()
@@ -52,27 +72,25 @@ asd igig cxxxncnc
os.Stdout = w
for mode, expect := range expects {
OutputMode = mode
fd := strings.NewReader(table)
data, err := parseFile(fd, "")
testname := fmt.Sprintf("print-%s", mode)
t.Run(testname, func(t *testing.T) {
if err != nil {
t.Errorf("Parser returned error: %s\nData processed so far: %+v", err, data)
}
OutputMode = mode
data := startdata // we need to reset our mock data, since it's being modified in printData()
printData(&data)
printData(&data)
buf := make([]byte, 1024)
n, err := r.Read(buf)
if err != nil {
t.Fatal(err)
}
buf = buf[:n]
output := strings.TrimSpace(string(buf))
buf := make([]byte, 1024)
n, err := r.Read(buf)
if err != nil {
t.Fatal(err)
}
buf = buf[:n]
output := strings.TrimSpace(string(buf))
if output != expect {
t.Errorf("output mode: %s, got:\n%s\nwant:\n%s\n (%d <=> %d)", mode, output, expect, len(output), len(expect))
}
if output != expect {
t.Errorf("output mode: %s, got:\n%s\nwant:\n%s\n (%d <=> %d)", mode, output, expect, len(output), len(expect))
}
})
}
// Restore