Skip to content

Commit 1a4d9ed

Browse files
author
Andreas Behringer
authored
Merge pull request #3 from behringer24/test/creating_first_tests
Add unit and integration tests
2 parents 47890b7 + fcd955d commit 1a4d9ed

File tree

6 files changed

+372
-0
lines changed

6 files changed

+372
-0
lines changed

.github/workflows/go.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# This workflow will build a golang project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3+
4+
name: Build + Test
5+
6+
on:
7+
push:
8+
pull_request:
9+
branches: [ "main" ]
10+
11+
jobs:
12+
13+
build:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v3
17+
18+
- name: Set up Go
19+
uses: actions/setup-go@v3
20+
with:
21+
go-version: 1.20
22+
23+
- name: Build
24+
run: go build -v ./...
25+
26+
- name: Test
27+
run: go test -v ./...

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# argumentative
22
Go argument parser fast and simple
33

4+
[![Build + Test](https://github.com/behringer24/argumentative/actions/workflows/go.yml/badge.svg)](https://github.com/behringer24/argumentative/actions/workflows/go.yml)
5+
46
## Why
57
I experimented with a lot of Go command line argument parsers to build simple but powerful cli applications. I like the way that pythons _argparse_ module works, but did not find a suitable replacemant for my current Go projects. Some seem to be abandoned and even the big framework-like tools did not handle positional arguments like I would like them to work. So this is because and because: Why not?
68

argumentative_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package argumentative
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"log"
7+
"os"
8+
"sync"
9+
"testing"
10+
)
11+
12+
func captureOutput(f func()) string {
13+
reader, writer, err := os.Pipe()
14+
if err != nil {
15+
panic(err)
16+
}
17+
stdout := os.Stdout
18+
stderr := os.Stderr
19+
defer func() {
20+
os.Stdout = stdout
21+
os.Stderr = stderr
22+
log.SetOutput(os.Stderr)
23+
}()
24+
os.Stdout = writer
25+
os.Stderr = writer
26+
log.SetOutput(writer)
27+
out := make(chan string)
28+
wg := new(sync.WaitGroup)
29+
wg.Add(1)
30+
go func() {
31+
var buf bytes.Buffer
32+
wg.Done()
33+
io.Copy(&buf, reader)
34+
out <- buf.String()
35+
}()
36+
wg.Wait()
37+
f()
38+
writer.Close()
39+
return <-out
40+
}
41+
42+
func TestFlagsIntegration(t *testing.T) {
43+
flags := &Flags{}
44+
stringflag := flags.Flags().AddString("stringname", "s", true, "", "stringdescription")
45+
boolflag := flags.Flags().AddBool("boolname", "b", "booldescription")
46+
positional := flags.Flags().AddPositional("positionalname", false, "positionaldefault", "positionaldescription")
47+
48+
var args []string
49+
50+
args = append(args, "scriptname")
51+
err := flags.Parse(args)
52+
53+
await := "required flag --stringname missing"
54+
55+
if err == nil {
56+
t.Errorf("No error found, got [%p], want pointer", err)
57+
} else if err.Error() != await {
58+
t.Errorf("Wrong error message, got [%s], want [%s]", err, await)
59+
}
60+
61+
if *stringflag != "" {
62+
t.Errorf("Wrong stringflag value, got [%s], want [%s]", *stringflag, "")
63+
}
64+
65+
if *boolflag != false {
66+
t.Errorf("Wrong boolflag value, got [%t], want [%t]", *boolflag, false)
67+
}
68+
69+
if *positional != "positionaldefault" {
70+
t.Errorf("Wrong positional value, got [%s], want [%s]", *positional, "positionaldefault")
71+
}
72+
73+
args = append(args, "-s", "stringvalue", "-b", "positionalvalue")
74+
err = flags.Parse(args)
75+
76+
await = "required flag --stringname missing"
77+
78+
if err != nil {
79+
t.Errorf("Error found, got [%s], want nil", err.Error())
80+
}
81+
82+
if *stringflag != "stringvalue" {
83+
t.Errorf("Wrong stringflag value, got [%s], want [%s]", *stringflag, "stringvalue")
84+
}
85+
86+
if *boolflag != true {
87+
t.Errorf("Wrong boolflag value, got [%t], want [%t]", *boolflag, false)
88+
}
89+
90+
if *positional != "positionalvalue" {
91+
t.Errorf("Wrong positional value, got [%s], want [%s]", *positional, "positionalvalue")
92+
}
93+
}
94+
95+
func TestUsage(t *testing.T) {
96+
flags := &Flags{}
97+
flags.Flags().AddString("stringname", "s", true, "", "stringdescription")
98+
flags.Flags().AddBool("boolname", "b", "booldescription")
99+
flags.Flags().AddPositional("positionalname", false, "positionaldefault", "positionaldescription")
100+
101+
await := `title
102+
description
103+
104+
Usage: title [-b] -s [positionalname]
105+
106+
Flags:
107+
-b, --boolname booldescription
108+
109+
Options:
110+
-s, --stringname stringdescription
111+
112+
Positional arguments:
113+
positionalname positionaldescription (Default: positionaldefault)
114+
`
115+
116+
result := captureOutput(func() {
117+
flags.Usage("title", "description", nil)
118+
})
119+
120+
if result != await {
121+
t.Errorf("Wrong Usage output, got\n%s\n\nwant\n\n%s", result, await)
122+
}
123+
}

boolflag_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package argumentative
2+
3+
import "testing"
4+
5+
func TestNewBoolFlag(t *testing.T) {
6+
flag := NewBoolFlag("longname", "s", "description")
7+
8+
if flag.Longflag != "longname" {
9+
t.Errorf("Longflag assignment wrong, got [%s], want [%s]", flag.Longflag, "longname")
10+
}
11+
12+
if flag.Shortflag != "s" {
13+
t.Errorf("Shortflag assignment wrong, got [%s], want [%s]", flag.Shortflag, "s")
14+
}
15+
16+
if flag.Description != "description" {
17+
t.Errorf("Description assignment wrong, got [%s], want [%s]", flag.Description, "description")
18+
}
19+
20+
if *flag.Value != false {
21+
t.Errorf("Assignment of default to value wrong, got [%t], want [%t]", *flag.Value, false)
22+
}
23+
}
24+
25+
func TestGetLongBoolDescription(t *testing.T) {
26+
flag := NewBoolFlag("longname", "s", "description")
27+
result := flag.GetLongDescription()
28+
await := "-s, --longname description"
29+
30+
if result != await {
31+
t.Errorf("Generation of long description failed, got [%s], want [%s]", result, await)
32+
}
33+
34+
flag = NewBoolFlag("longname", "", "description")
35+
result = flag.GetLongDescription()
36+
await = "--longname description"
37+
38+
if result != await {
39+
t.Errorf("Generation of long description without default failed, got [%s], want [%s]", result, await)
40+
}
41+
}
42+
43+
func TestGetShortBoolDescription(t *testing.T) {
44+
flag := NewBoolFlag("longname", "s", "description")
45+
result := flag.GetShortDescription()
46+
await := " [-s]" // @todo: remove space
47+
48+
if result != await {
49+
t.Errorf("Generation of short description failed, got [%s], want [%s]", result, await)
50+
}
51+
52+
flag = NewBoolFlag("longname", "", "description")
53+
result = flag.GetShortDescription()
54+
await = " [--longname]" // @todo remove space
55+
56+
if result != await {
57+
t.Errorf("Generation of short description no required failed, got [%s], want [%s]", result, await)
58+
}
59+
}

positional_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package argumentative
2+
3+
import "testing"
4+
5+
func TestNewPositional(t *testing.T) {
6+
flag := NewPositional("longname", true, "default", "description")
7+
8+
if flag.Longflag != "longname" {
9+
t.Errorf("Longflag assignment wrong, got [%s], want [%s]", flag.Longflag, "longname")
10+
}
11+
12+
if flag.Default != "default" {
13+
t.Errorf("Default assignment wrong, got [%s], want [%s]", flag.Default, "default")
14+
}
15+
16+
if flag.Description != "description" {
17+
t.Errorf("Description assignment wrong, got [%s], want [%s]", flag.Description, "description")
18+
}
19+
20+
if *flag.Value != "default" {
21+
t.Errorf("Assignment of default to value wrong, got [%s], want [%s]", *flag.Value, flag.Default)
22+
}
23+
}
24+
func TestGetLongPositionalDescription(t *testing.T) {
25+
flag := NewPositional("longname", true, "default", "description")
26+
result := flag.GetLongDescription()
27+
await := "longname description (Default: default)"
28+
29+
if result != await {
30+
t.Errorf("Generation of long description failed, got [%s], want [%s]", result, await)
31+
}
32+
33+
flag = NewPositional("longname", false, "default", "description")
34+
result = flag.GetLongDescription()
35+
await = "longname description (Default: default)"
36+
37+
if result != await {
38+
t.Errorf("Generation of long description not required failed, got [%s], want [%s]", result, await)
39+
}
40+
41+
flag = NewPositional("longname", false, "", "description")
42+
result = flag.GetLongDescription()
43+
await = "longname description"
44+
45+
if result != await {
46+
t.Errorf("Generation of long description no default failed, got [%s], want [%s]", result, await)
47+
}
48+
}
49+
50+
func TestGetShortPositionalDescription(t *testing.T) {
51+
flag := NewPositional("longname", true, "default", "description")
52+
result := flag.GetShortDescription()
53+
await := " longname" // @todo: remove space
54+
55+
if result != await {
56+
t.Errorf("Generation of short description failed, got [%s], want [%s]", result, await)
57+
}
58+
59+
flag = NewPositional("longname", false, "", "description")
60+
result = flag.GetShortDescription()
61+
await = " [longname]" // @todo remove space
62+
63+
if result != await {
64+
t.Errorf("Generation of short description no required failed, got [%s], want [%s]", result, await)
65+
}
66+
67+
flag = NewPositional("longname", false, "default", "description")
68+
result = flag.GetShortDescription()
69+
await = " [longname]" // @todo remove space
70+
71+
if result != await {
72+
t.Errorf("Generation of short description no required but default failed, got [%s], want [%s]", result, await)
73+
}
74+
}

stringflag_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package argumentative
2+
3+
import "testing"
4+
5+
func TestNewStringFlag(t *testing.T) {
6+
flag := NewStringFlag("longname", "s", true, "default", "description")
7+
8+
if flag.Longflag != "longname" {
9+
t.Errorf("Longflag assignment wrong, got [%s], want [%s]", flag.Longflag, "longname")
10+
}
11+
12+
if flag.Shortflag != "s" {
13+
t.Errorf("Shortflag assignment wrong, got [%s], want [%s]", flag.Shortflag, "s")
14+
}
15+
16+
if flag.Default != "default" {
17+
t.Errorf("Default assignment wrong, got [%s], want [%s]", flag.Default, "default")
18+
}
19+
20+
if flag.Description != "description" {
21+
t.Errorf("Description assignment wrong, got [%s], want [%s]", flag.Description, "description")
22+
}
23+
24+
if *flag.Value != "default" {
25+
t.Errorf("Assignment of default to value wrong, got [%s], want [%s]", *flag.Value, flag.Default)
26+
}
27+
}
28+
29+
func TestGetLongDescription(t *testing.T) {
30+
flag := NewStringFlag("longname", "s", true, "default", "description")
31+
result := flag.GetLongDescription()
32+
await := "-s, --longname description (Default: default)"
33+
34+
if result != await {
35+
t.Errorf("Generation of long description failed, got [%s], want [%s]", result, await)
36+
}
37+
38+
flag = NewStringFlag("longname", "s", true, "", "description")
39+
result = flag.GetLongDescription()
40+
await = "-s, --longname description"
41+
42+
if result != await {
43+
t.Errorf("Generation of long description without default failed, got [%s], want [%s]", result, await)
44+
}
45+
46+
flag = NewStringFlag("longname", "s", false, "", "description")
47+
result = flag.GetLongDescription()
48+
await = "-s, --longname description"
49+
50+
if result != await {
51+
t.Errorf("Generation of long description without default failed, got [%s], want [%s]", result, await)
52+
}
53+
54+
flag = NewStringFlag("longname", "", true, "", "description")
55+
result = flag.GetLongDescription()
56+
await = "--longname description"
57+
58+
if result != await {
59+
t.Errorf("Generation of long description without shortname failed, got [%s], want [%s]", result, await)
60+
}
61+
}
62+
63+
func TestGetShortDescription(t *testing.T) {
64+
flag := NewStringFlag("longname", "s", true, "default", "description")
65+
result := flag.GetShortDescription()
66+
await := " -s" // @todo: remove space
67+
68+
if result != await {
69+
t.Errorf("Generation of short description failed, got [%s], want [%s]", result, await)
70+
}
71+
72+
flag = NewStringFlag("longname", "s", false, "", "description")
73+
result = flag.GetShortDescription()
74+
await = " [-s]" // @todo remove space
75+
76+
if result != await {
77+
t.Errorf("Generation of short description no required failed, got [%s], want [%s]", result, await)
78+
}
79+
80+
flag = NewStringFlag("longname", "", false, "", "description")
81+
result = flag.GetShortDescription()
82+
await = " [--longname]" // @todo remove space
83+
84+
if result != await {
85+
t.Errorf("Generation of short description no short name failed, got [%s], want [%s]", result, await)
86+
}
87+
}

0 commit comments

Comments
 (0)