summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rwxr-xr-xtests/cli-opts.sh106
-rw-r--r--tests/functional/string-round-trip/uuid.go23
l---------tests/fuzz/new-v4-from/main.go (renamed from tests/fuzz/new-from/main.go)0
-rw-r--r--tests/fuzz/new-v4-from/uuid.go (renamed from tests/fuzz/new-from/uuid.go)2
l---------tests/fuzz/new-v7-from/main.go1
-rw-r--r--tests/fuzz/new-v7-from/uuid.go33
-rw-r--r--tests/uuid.go387
7 files changed, 530 insertions, 22 deletions
diff --git a/tests/cli-opts.sh b/tests/cli-opts.sh
index 39f01f4..1d7cab8 100755
--- a/tests/cli-opts.sh
+++ b/tests/cli-opts.sh
@@ -4,6 +4,85 @@ set -eu
. tests/lib.sh
+test_unsupported_flags() {
+ testing 'unsupported flags'
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ./uuid.bin -x 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 2
+ assert_empty_stdout
+ assert_grep_stderr '^Usage:$'
+ rm "$OUT" "$ERR"
+
+ test_ok
+}
+
+test_flag_without_required_arguments() {
+ testing 'flag without required arguments'
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ./uuid.bin -v 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 2
+ assert_empty_stdout
+ assert_grep_stderr '^Usage:$'
+ rm "$OUT" "$ERR"
+
+ test_ok
+}
+
+test_flag_with_bad_argument_value() {
+ testing 'flag without required arguments'
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ./uuid.bin -v 1 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 2
+ assert_empty_stdout
+ assert_grep_stderr '^Usage:$'
+ rm "$OUT" "$ERR"
+
+ test_ok
+}
+
+test_generates_uuid_with_custom_version() {
+ testing 'UUID with custom version'
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ./uuid.bin -v 4 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 0
+ assert_grep_stdout '^.{,14}4'
+ assert_empty_stderr
+ rm "$OUT" "$ERR"
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ./uuid.bin -v 7 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 0
+ assert_grep_stdout '^.{,14}7'
+ assert_empty_stderr
+ rm "$OUT" "$ERR"
+
+ test_ok
+}
+
test_generates_uuid_with_0_args() {
testing 'generates UUID with 0 arguments'
@@ -28,7 +107,8 @@ test_checks_string_with_1_arg() {
ERR="$(mkstemp)"
trap 'rm -f "$OUT" "$ERR"' EXIT
STATUS=0
- ./uuid.bin 'cac94e13-41fa-40c4-bd46-5b7b3b46c09e' 1>"$OUT" 2>"$ERR" || STATUS=$?
+ ID='cac94e13-41fa-40c4-bd46-5b7b3b46c09e'
+ ./uuid.bin "$ID" 1>"$OUT" 2>"$ERR" || STATUS=$?
assert_status 0
assert_empty_stdout
assert_empty_stderr
@@ -48,7 +128,31 @@ test_checks_string_with_1_arg() {
test_ok
}
+test_checks_string_with_1_arg_ignores_options() {
+ testing 'checks string with 1 arg ignores options'
+
+ N="$LINENO"
+ OUT="$(mkstemp)"
+ ERR="$(mkstemp)"
+ trap 'rm -f "$OUT" "$ERR"' EXIT
+ STATUS=0
+ ID='cac94e13-41fa-40c4-bd46-5b7b3b46c09e'
+ ID='76600ea2-0282-4b38-9bc9-dd69125445f3'
+ ./uuid.bin -v 4 "$ID" 1>"$OUT" 2>"$ERR" || STATUS=$?
+ assert_status 0
+ assert_empty_stdout
+ assert_empty_stderr
+ rm "$OUT" "$ERR"
+
+ test_ok
+}
+
+test_unsupported_flags
+test_flag_without_required_arguments
test_generates_uuid_with_0_args
+test_flag_with_bad_argument_value
+test_generates_uuid_with_custom_version
test_checks_string_with_1_arg
+test_checks_string_with_1_arg_ignores_options
diff --git a/tests/functional/string-round-trip/uuid.go b/tests/functional/string-round-trip/uuid.go
index 000d3fb..82414ea 100644
--- a/tests/functional/string-round-trip/uuid.go
+++ b/tests/functional/string-round-trip/uuid.go
@@ -45,16 +45,31 @@ func assertEq(given any, expected any) {
func MainTest() {
- testing("string is the same after round-trip", func() {
- str1 := New().String()
+ testing("v4 string is the same after round-trip", func() {
+ str1 := NewV4().String()
id, err := FromString(str1)
assertEq(err, nil)
str2 := id.String()
assertEq(str1, str2)
})
- testing("UUID is the same after round-trip", func() {
- id1 := New()
+ testing("v4 UUID is the same after round-trip", func() {
+ id1 := NewV4()
+ id2, err := FromString(id1.String())
+ assertEq(err, nil)
+ assertEq(id1, id2)
+ })
+
+ testing("v7 string is the same after round-trip", func() {
+ str1 := NewV7().String()
+ id, err := FromString(str1)
+ assertEq(err, nil)
+ str2 := id.String()
+ assertEq(str1, str2)
+ })
+
+ testing("v7 UUID is the same after round-trip", func() {
+ id1 := NewV7()
id2, err := FromString(id1.String())
assertEq(err, nil)
assertEq(id1, id2)
diff --git a/tests/fuzz/new-from/main.go b/tests/fuzz/new-v4-from/main.go
index f67563d..f67563d 120000
--- a/tests/fuzz/new-from/main.go
+++ b/tests/fuzz/new-v4-from/main.go
diff --git a/tests/fuzz/new-from/uuid.go b/tests/fuzz/new-v4-from/uuid.go
index 298687b..90cc994 100644
--- a/tests/fuzz/new-from/uuid.go
+++ b/tests/fuzz/new-v4-from/uuid.go
@@ -11,7 +11,7 @@ import (
func fn(f *testing.F) {
f.Fuzz(func(t *testing.T, payload []byte) {
- NewFrom(bytes.NewReader(payload))
+ NewV4From(bytes.NewReader(payload))
})
}
diff --git a/tests/fuzz/new-v7-from/main.go b/tests/fuzz/new-v7-from/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/fuzz/new-v7-from/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/fuzz/new-v7-from/uuid.go b/tests/fuzz/new-v7-from/uuid.go
new file mode 100644
index 0000000..8686ebf
--- /dev/null
+++ b/tests/fuzz/new-v7-from/uuid.go
@@ -0,0 +1,33 @@
+package uuid
+
+import (
+ "bytes"
+ "os"
+ "testing"
+ "testing/internal/testdeps"
+)
+
+
+
+func fn(f *testing.F) {
+ f.Fuzz(func(t *testing.T, payload []byte, nanosecs uint64) {
+ NewV7From(bytes.NewReader(payload), func() uint64 {
+ return nanosecs
+ })
+ })
+}
+
+
+
+func MainTest() {
+ fuzzTargets := []testing.InternalFuzzTarget{
+ { "fn", fn },
+ }
+
+ deps := testdeps.TestDeps{}
+ tests := []testing.InternalTest {}
+ benchmarks := []testing.InternalBenchmark{}
+ examples := []testing.InternalExample {}
+ m := testing.MainStart(deps, tests, benchmarks, fuzzTargets, examples)
+ os.Exit(m.Run())
+}
diff --git a/tests/uuid.go b/tests/uuid.go
index ad9cac4..912339a 100644
--- a/tests/uuid.go
+++ b/tests/uuid.go
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
+ "io"
"os"
"reflect"
"strings"
@@ -50,18 +51,24 @@ func assertEq(given any, expected any) {
}
-func test_NewFrom() {
- testStart("NewFrom()")
+
+func test_NewV4From() {
+ testStart("NewV4From()")
+
+ testing("we propagate the error when it happens", func() {
+ _, err := NewV4From(strings.NewReader(""))
+ assertEq(err, io.EOF)
+ })
testing("we get the same UUID from the same input", func() {
const s = "abcdefghijklmnop"
r1 := strings.NewReader(s)
- uuid1, err := NewFrom(r1)
+ uuid1, err := NewV4From(r1)
assertEq(err, nil)
r2 := strings.NewReader(s)
- uuid2, err := NewFrom(r2)
+ uuid2, err := NewV4From(r2)
assertEq(err, nil)
assertEq(uuid1, uuid2)
@@ -107,7 +114,7 @@ func test_NewFrom() {
}
r := bytes.NewReader(input)
- given, err := NewFrom(r)
+ given, err := NewV4From(r)
assertEq(err, nil)
assertEq(given, expected)
})
@@ -152,30 +159,166 @@ func test_NewFrom() {
}
r := bytes.NewReader(input)
- given, err := NewFrom(r)
+ given, err := NewV4From(r)
assertEq(err, nil)
assertEq(given, expected)
})
}
-func test_New() {
- testStart("New()")
+func test_NewV4() {
+ testStart("NewV4()")
testing("we can generate UUID values: ", func() {
- var uuid UUID = New()
- assertEq(len(uuid), 16)
+ var uuid UUID = NewV4()
+ assertEq(uuid == Nil, false)
+ assertEq(uuid == Max, false)
})
testing("panic when the randomReader fails", func() {
savedReader := randomReader
- randomReader = strings.NewReader("abc")
+ randomReader = strings.NewReader("")
+ defer func() {
+ r := recover()
+ assertEq(r, io.EOF)
+ randomReader = savedReader
+ }()
+
+ NewV4()
+ os.Exit(5)
+ })
+}
+
+func test_NewV7From() {
+ testStart("NewV7From()")
+
+ testing("reader error is propagated", func() {
+ nowFn := func() uint64 {
+ return 0
+ }
+
+ _, err := NewV7From(strings.NewReader(""), nowFn)
+ assertEq(err, io.EOF)
+ })
+
+ testing("we get the same UUID given the same input", func() {
+ const s = "abcdefgh"
+ nowFn := func() uint64 {
+ return 0
+ }
+
+ r1 := strings.NewReader(s)
+ uuid1, err := NewV7From(r1, nowFn)
+ assertEq(err, nil)
+
+ r2 := strings.NewReader(s)
+ uuid2, err := NewV7From(r2, nowFn)
+ assertEq(err, nil)
+
+ assertEq(uuid1, uuid2)
+ })
+
+ testing("the bytes are what the reader plus the time gives", func() {
+ randomInput := []byte{
+ 0x00,
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ }
+
+ nowFn := func() uint64 {
+ return 0xffffffff00000000
+ }
+
+ expected := UUID{
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0x00,
+ 0x00,
+ 0x00 + 0x70,
+ 0x00,
+ 0x00 + 0x80,
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ }
+
+ r := bytes.NewReader(randomInput)
+ given, err := NewV7From(r, nowFn)
+ assertEq(err, nil)
+ assertEq(given, expected)
+ })
+
+ testing("v7 and variant markers", func() {
+ randomInput := []byte{
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ }
+
+ nowFn := func() uint64 {
+ return 0x1111111111111111
+ }
+
+ expected := UUID{
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x71, // not 0x11
+ 0x11,
+ 0x91, // not 0x11
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ 0x11,
+ }
+
+ r := bytes.NewReader(randomInput)
+ given, err := NewV7From(r, nowFn)
+ assertEq(err, nil)
+ assertEq(given, expected)
+ })
+}
+
+func test_NewV7() {
+ testStart("NewV7()")
+
+ testing("we can generate UUID values: ", func() {
+ var uuid UUID = NewV7()
+ assertEq(uuid == Nil, false)
+ assertEq(uuid == Max, false)
+ })
+
+ testing("panic when reader fails", func() {
+ savedReader := randomReader
+ randomReader = strings.NewReader("")
defer func() {
r := recover()
- assertEq(r == nil, false)
+ assertEq(r, io.EOF)
randomReader = savedReader
}()
- New()
+ NewV7()
os.Exit(5)
})
}
@@ -224,7 +367,7 @@ func test_FromString() {
testing("UUID -> string -> UUID round trip", func() {
for i := 0; i < 100; i++ {
- uuid0 := New()
+ uuid0 := NewV4()
uuid1, err := FromString(uuid0.String())
assertEq(err, nil)
assertEq(uuid0, uuid1)
@@ -251,11 +394,223 @@ func test_FromString() {
})
}
+func test_usage() {
+ testStart("usage()")
+
+ testing("all it does is write to the given io.Writer", func() {
+ w := strings.Builder{}
+ usage("xxx", &w)
+
+ const expectedRaw = `
+ Usage:
+ xxx [-v (4|7)]
+ xxx STRING
+ `
+ expected := strings.Trim(
+ strings.ReplaceAll(expectedRaw, "\t", ""),
+ "\n",
+ ) + "\n"
+ assertEq(w.String(), expected)
+ })
+}
+
+func test_actionForSubargs() {
+ testStart("actionForSubargs()")
+
+ testing("we decide based only on length", func() {
+ assertEq(actionForSubargs([]string{}), actionType_generate)
+ assertEq(actionForSubargs([]string{""}), actionType_parse)
+ assertEq(actionForSubargs([]string{"id"}), actionType_parse)
+ })
+}
+
+func test_getopt() {
+ testStart("getopt()")
+
+ const usageRaw = `
+ Usage:
+ $0 [-v (4|7)]
+ $0 STRING
+ `
+ usage := strings.Trim(
+ strings.ReplaceAll(usageRaw, "\t", ""),
+ "\n",
+ ) + "\n"
+
+ testing("we supress the default error message", func() {
+ w := strings.Builder{}
+ argv := []string{"$0", "-h"}
+ _, rc := getopt(argv, &w)
+
+ assertEq(w.String(), usage)
+ assertEq(rc, 2)
+ })
+
+ testing("we get unsupported flag error", func() {
+ w := strings.Builder{}
+ argv := []string{"$0", "-Z"}
+ _, rc := getopt(argv, &w)
+
+ const message = "flag provided but not defined: -Z\n"
+ assertEq(w.String(), message + usage)
+ assertEq(rc, 2)
+ })
+
+ testing("we get incorrect use of flag error", func() {
+ w := strings.Builder{}
+ argv := []string{"$0", "-v"}
+ _, rc := getopt(argv, &w)
+
+ const message = "flag needs an argument: -v\n"
+ assertEq(w.String(), message + usage)
+ assertEq(rc, 2)
+ })
+
+ testing("we get bad flag value error", func() {
+ w := strings.Builder{}
+ argv := []string{"$0", "-v", "a"}
+ _, rc := getopt(argv, &w)
+
+ const message = "invalid value \"a\" for flag -v: parse error\n"
+ assertEq(w.String(), message + usage)
+ assertEq(rc, 2)
+ })
+
+ testing("the args has the picked version", func() {
+ var (
+ w1 = strings.Builder{}
+ w2 = strings.Builder{}
+ w3 = strings.Builder{}
+ )
+
+ argsIn1 := []string{"$0"}
+ argsIn2 := []string{"$0", "-v", "4"}
+ argsIn3 := []string{"$0", "-v", "7"}
+
+ args1, rc1 := getopt(argsIn1, &w1)
+ args2, rc2 := getopt(argsIn2, &w2)
+ args3, rc3 := getopt(argsIn3, &w3)
+
+ expected1 := argsT{
+ allArgs: []string{"$0"},
+ subArgs: []string{},
+ action: actionType_generate,
+ version: 4,
+ }
+ expected2 := argsT{
+ allArgs: []string{"$0", "-v", "4"},
+ subArgs: []string{},
+ action: actionType_generate,
+ version: 4,
+ }
+ expected3 := argsT{
+ allArgs: []string{"$0", "-v", "7"},
+ subArgs: []string{},
+ action: actionType_generate,
+ version: 7,
+ }
+
+ assertEq(w1.String(), "")
+ assertEq(w2.String(), "")
+ assertEq(w3.String(), "")
+ assertEq(rc1, 0)
+ assertEq(rc2, 0)
+ assertEq(rc3, 0)
+ assertEq(args1, expected1)
+ assertEq(args2, expected2)
+ assertEq(args3, expected3)
+ })
+
+ testing("the args has the picked action", func() {
+ var (
+ w1 = strings.Builder{}
+ w2 = strings.Builder{}
+ )
+
+ argsIn1 := []string{"$0", "the-string"}
+ argsIn2 := []string{"$0", "-v", "7", "the-string"}
+
+ args1, rc1 := getopt(argsIn1, &w1)
+ args2, rc2 := getopt(argsIn2, &w2)
+
+ expected1 := argsT{
+ allArgs: []string{"$0", "the-string"},
+ subArgs: []string{"the-string"},
+ action: actionType_parse,
+ version: 4,
+ }
+ expected2 := argsT{
+ allArgs: []string{"$0", "-v", "7", "the-string"},
+ subArgs: []string{"the-string"},
+ action: actionType_parse,
+ version: 7,
+ }
+
+ assertEq(w1.String(), "")
+ assertEq(w2.String(), "")
+ assertEq(rc1, 0)
+ assertEq(rc2, 0)
+ assertEq(args1, expected1)
+ assertEq(args2, expected2)
+ })
+}
+
+func test_run() {
+ testStart("run()")
+
+ testing("generating IDs gives us 0 rc", func() {
+ out1 := strings.Builder{}
+ out2 := strings.Builder{}
+ args1 := argsT{
+ action: actionType_generate,
+ version: 4,
+ }
+ args2 := argsT{
+ action: actionType_generate,
+ version: 7,
+ }
+
+ rc1 := run(args1, nil, &out1, nil)
+ rc2 := run(args2, nil, &out2, nil)
+
+ assertEq(rc1, 0)
+ assertEq(rc2, 0)
+ assertEq(len(out1.String()), encodedLength + len("\n"))
+ assertEq(len(out2.String()), encodedLength + len("\n"))
+ })
+
+ testing("parsing varies based on ID validity", func() {
+ const id = "ggggggg-ggggg-gggg-gggg-gggggggggggg"
+ err1 := strings.Builder{}
+ args1 := argsT{
+ action: actionType_parse,
+ subArgs: []string{ id },
+ }
+ args2 := argsT{
+ action: actionType_parse,
+ subArgs: []string{New().String()},
+ }
+
+ rc1 := run(args1, nil, nil, &err1)
+ rc2 := run(args2, nil, nil, nil)
+
+ assertEq(rc1, 3)
+ assertEq(rc2, 0)
+ assertEq(err1.String(), "uuid: Bad char in string\n")
+ })
+}
+
func MainTest() {
- test_NewFrom()
- test_New()
+ test_NewV4From()
+ test_NewV4()
+ test_NewV7From()
+ test_NewV7()
test_String()
test_FromString()
+ test_usage()
+ test_actionForSubargs()
+ test_getopt()
+ test_run()
}