summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2024-08-06 10:25:30 -0300
committerEuAndreh <eu@euandre.org>2024-08-06 10:25:30 -0300
commit27f238f52c79835fb924e9ca738c12344630cac7 (patch)
treede805031261d47712c446964adee3970bd699db0
parentStart using TestStart() and Testing() (diff)
downloadgobang-27f238f52c79835fb924e9ca738c12344630cac7.tar.gz
gobang-27f238f52c79835fb924e9ca738c12344630cac7.tar.xz
Add tests for UUID functions
-rw-r--r--src/gobang.go143
-rw-r--r--tests/gobang.go126
2 files changed, 220 insertions, 49 deletions
diff --git a/src/gobang.go b/src/gobang.go
index 4775dfc..dc0d9bc 100644
--- a/src/gobang.go
+++ b/src/gobang.go
@@ -33,9 +33,14 @@ const (
LevelDebug logLevel = 4
)
-const lengthUUID = 16
+
+const (
+ uuidDashCount = 4
+ uuidByteCount = 16
+ uuidEncodedLength = (uuidByteCount * 2) + uuidDashCount
+)
type UUID struct {
- bytes [lengthUUID]byte
+ bytes [uuidByteCount]byte
}
type Gauge struct {
@@ -54,7 +59,7 @@ type CopyResult struct {
const maxInt = int((^uint(0)) >> 1)
const (
- scrypt_N = 32768
+ scrypt_N = 1 << 15
scrypt_r = 8
scrypt_p = 1
scryptSaltMinLength = 32
@@ -62,7 +67,6 @@ const (
)
-
// Private variables
// lastV7time is the last time we returned stored as:
@@ -125,7 +129,7 @@ func _PBKDF2Key(
hashLen := prf.Size()
numBlocks := (keyLen + hashLen - 1) / hashLen
- var buf [4]byte
+ var buffer [4]byte
dk := make([]byte, 0, numBlocks*hashLen)
U := make([]byte, hashLen)
for block := 1; block <= numBlocks; block++ {
@@ -134,11 +138,11 @@ func _PBKDF2Key(
// U_1 = PRF(password, salt || uint(i))
prf.Reset()
prf.Write(salt)
- buf[0] = byte(block >> 24)
- buf[1] = byte(block >> 16)
- buf[2] = byte(block >> 8)
- buf[3] = byte(block >> 0)
- prf.Write(buf[:4])
+ buffer[0] = byte(block >> 24)
+ buffer[1] = byte(block >> 16)
+ buffer[2] = byte(block >> 8)
+ buffer[3] = byte(block >> 0)
+ prf.Write(buffer[:4])
dk = prf.Sum(dk)
T := dk[len(dk) - hashLen:]
copy(U, T)
@@ -380,16 +384,27 @@ func scrypt(
return _PBKDF2Key(password, b, 1, keyLen, sha256.New), nil
}
-func Salt() []byte {
- var buf [scryptSaltMinLength]byte
- _, err := io.ReadFull(rand.Reader, buf[:])
+func Random(length int) []byte {
+ buffer := make([]byte, length)
+ _, err := io.ReadFull(rand.Reader, buffer)
FatalIf(err)
- return buf[:]
+ return buffer
+}
+
+func Salt() []byte {
+ return Random(scryptSaltMinLength)
}
func Hash(password []byte, salt []byte) []byte{
Assert(len(salt) >= scryptSaltMinLength, "salt is too small")
- hash, err := scrypt(password, salt, scrypt_N, scrypt_r, scrypt_p, scryptDesiredLength)
+ hash, err := scrypt(
+ password,
+ salt,
+ scrypt_N,
+ scrypt_r,
+ scrypt_p,
+ scryptDesiredLength,
+ )
FatalIf(err)
return hash
}
@@ -410,42 +425,43 @@ func getV7Time(nano int64) (int64, int64) {
timeMutex.Lock()
defer timeMutex.Unlock()
if now <= lastV7Time {
- now = lastV7Time + 1
+ now = lastV7Time + 1
milli = now >> 12
- seq = now & 0xfff
+ seq = now & 0xfff
}
lastV7Time = now
return milli, seq
}
-func NewUUID() UUID {
- var buf [lengthUUID]byte
- _, err := io.ReadFull(rand.Reader, buf[7:])
- if err != nil {
- panic(err)
- }
+func newUUIDFrom(randomBuffer [uuidByteCount]byte, now int64) UUID {
+ randomBuffer[6] = (randomBuffer[6] & 0x0f) | 0x40 // Version 4
+ randomBuffer[8] = (randomBuffer[8] & 0x3f) | 0x80 // Variant is 10
- buf[6] = (buf[6] & 0x0f) | 0x40 // Version 4
- buf[8] = (buf[8] & 0x3f) | 0x80 // Variant is 10
+ t, s := getV7Time(now)
- t, s := getV7Time(time.Now().UnixNano())
+ randomBuffer[0] = byte(t >> 40)
+ randomBuffer[1] = byte(t >> 32)
+ randomBuffer[2] = byte(t >> 24)
+ randomBuffer[3] = byte(t >> 16)
+ randomBuffer[4] = byte(t >> 8)
+ randomBuffer[5] = byte(t >> 0)
- buf[0] = byte(t >> 40)
- buf[1] = byte(t >> 32)
- buf[2] = byte(t >> 24)
- buf[3] = byte(t >> 16)
- buf[4] = byte(t >> 8)
- buf[5] = byte(t >> 0)
+ randomBuffer[6] = 0x70 | (0x0f & byte(s >> 8))
+ randomBuffer[7] = byte(s)
+ return UUID { bytes: randomBuffer }
+}
+
+func NewUUID() UUID {
+ var buffer [uuidByteCount]byte
+ _, err := io.ReadFull(rand.Reader, buffer[7:])
+ FatalIf(err)
- buf[6] = 0x70 | (0x0f & byte(s >> 8))
- buf[7] = byte(s)
- return UUID { bytes: buf }
+ now := time.Now().UnixNano()
+ return newUUIDFrom(buffer, now)
}
-func (uuid UUID) ToString() string {
- const dashCount = 4
- const encodedLength = (lengthUUID * 2) + dashCount
- dst := [encodedLength]byte {
+func (uuid UUID) String() string {
+ dst := [uuidEncodedLength]byte {
0, 0, 0, 0,
0, 0, 0, 0,
'-',
@@ -469,6 +485,37 @@ func (uuid UUID) ToString() string {
return string(dst[:])
}
+var (
+ dashIndexes = []int { 8, 13, 18, 23 }
+ emptyUUID = UUID {}
+ badUUIDLengthError = errors.New("str isn't of the correct length")
+ badUUIDDashCountError = errors.New("Bad count of dashes in string")
+ badUUIDDashPositionError = errors.New("Bad char in string")
+)
+func ParseUUID(str string) (UUID, error) {
+ if len(str) != uuidEncodedLength {
+ return emptyUUID, badUUIDLengthError
+ }
+
+ if strings.Count(str, "-") != uuidDashCount {
+ return emptyUUID, badUUIDDashCountError
+ }
+
+ for _, idx := range dashIndexes {
+ if str[idx] != '-' {
+ return emptyUUID, badUUIDDashPositionError
+ }
+ }
+
+ hexstr := strings.Join(strings.Split(str, "-"), "")
+ data, err := hex.DecodeString(hexstr)
+ if err != nil {
+ return emptyUUID, err
+ }
+
+ return UUID { bytes: [uuidByteCount]byte(data) }, nil
+}
+
func Debug(message string, type_ string, args ...any) {
if level < LevelDebug {
return
@@ -478,7 +525,7 @@ func Debug(message string, type_ string, args ...any) {
message,
append(
[]any {
- "id", NewUUID().ToString(),
+ "id", NewUUID(),
"kind", "log",
"type", type_,
},
@@ -496,7 +543,7 @@ func Info(message string, type_ string, args ...any) {
message,
append(
[]any {
- "id", NewUUID().ToString(),
+ "id", NewUUID(),
"kind", "log",
"type", type_,
},
@@ -514,7 +561,7 @@ func Warning(message string, type_ string, args ...any) {
message,
append(
[]any {
- "id", NewUUID().ToString(),
+ "id", NewUUID(),
"kind", "log",
"type", type_,
},
@@ -532,7 +579,7 @@ func Error(message string, type_ string, args ...any) {
message,
append(
[]any {
- "id", NewUUID().ToString(),
+ "id", NewUUID(),
"kind", "log",
"type", type_,
},
@@ -550,7 +597,7 @@ func Metric(type_ string, label string, args ...any) {
"_",
append(
[]any {
- "id", NewUUID().ToString(),
+ "id", NewUUID(),
"kind", "metric",
"type", type_,
"label", label,
@@ -636,7 +683,11 @@ func TestStart(name string) {
func Testing(message string, body func()) {
if showColour() {
- fmt.Fprintf(os.Stderr, "\033[0;33mtesting\033[0m: %s... ", message)
+ fmt.Fprintf(
+ os.Stderr,
+ "\033[0;33mtesting\033[0m: %s... ",
+ message,
+ )
body()
fmt.Fprint(os.Stderr, "\033[0;32mOK\033[0m.\n")
} else {
@@ -682,7 +733,7 @@ func setLoggerOutput(w io.Writer) {
"info",
"pid", os.Getpid(),
"ppid", os.Getppid(),
- "puuid", NewUUID().ToString(),
+ "puuid", NewUUID(),
),
))
}
diff --git a/tests/gobang.go b/tests/gobang.go
index 61168d6..46cc9c5 100644
--- a/tests/gobang.go
+++ b/tests/gobang.go
@@ -5,10 +5,12 @@ import (
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
+ "encoding/hex"
"encoding/json"
"fmt"
"hash"
"log/slog"
+ "time"
)
@@ -324,11 +326,18 @@ func test_scrypt() {
Testing("example value", func() {
const expected = "lGnMz8io0AUkfzn6Pls1qX20Vs7PGN6sbYQ2TQgY12M="
- // DO NOT use this salt value; generate your own random salt. 8 bytes is
- // a good length.
+ // DO NOT use this salt value; generate your own random salt.
+ // 8 bytes is a good length.
salt := []byte{0xc8, 0x28, 0xf2, 0x58, 0xa7, 0x6a, 0xad, 0x7b}
- dk, err := scrypt([]byte("some password"), salt, 1<<15, 8, 1, 32)
+ dk, err := scrypt(
+ []byte("some password"),
+ salt,
+ 1<<15,
+ 8,
+ 1,
+ 32,
+ )
ErrorIf(err)
given := base64.StdEncoding.EncodeToString(dk)
@@ -336,6 +345,113 @@ func test_scrypt() {
})
}
+func test_newUUIDFrom() {
+ TestStart("newUUIDFrom()")
+
+ Testing("same UUID from same input", func() {
+ for i := 0; i < 100; i++ {
+ var b [uuidByteCount]byte
+ buffer := Random(uuidByteCount)
+ now := time.Now().UnixNano()
+
+ lastV7Time = now + 1
+ copy(b[:], buffer)
+ uuid1 := newUUIDFrom(b, now)
+
+ lastV7Time = now + 1
+ copy(b[:], buffer)
+ uuid2 := newUUIDFrom(b, now)
+
+ AssertEqual(uuid1, uuid2)
+ }
+ })
+}
+
+func test_NewUUID() {
+ TestStart("NewUUID()")
+
+ Testing("we can generate UUID values", func() {
+ var uuid UUID = NewUUID()
+ AssertEqual(len(uuid.bytes), uuidByteCount)
+ })
+}
+
+func test_UUIDString() {
+ TestStart("UUID.String()")
+
+ Testing("simple example values", func() {
+ uuids := []UUID {
+ UUID {
+ bytes: [uuidByteCount]byte {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ UUID {
+ bytes: [uuidByteCount]byte {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15,
+ },
+ },
+ UUID {
+ bytes: [uuidByteCount]byte {
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ },
+ },
+ UUID {
+ bytes: [uuidByteCount]byte {
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ },
+ },
+ }
+
+ strs := []string {
+ "00000000-0000-0000-0000-000000000000",
+ "00010203-0405-0607-0809-0a0b0c0d0e0f",
+ "dededede-dede-dede-dede-dededededede",
+ "ffffffff-ffff-ffff-ffff-ffffffffffff",
+ }
+
+ for i := range uuids {
+ AssertEqual(uuids[i].String(), strs[i])
+ }
+ })
+}
+
+func test_ParseUUID() {
+ TestStart("ParseUUID()")
+
+ Testing("UUID -> string -> UUID round trip", func() {
+ for i := 0; i < 100; i++ {
+ uuid0 := NewUUID()
+ uuid1, err := ParseUUID(uuid0.String())
+ ErrorIf(err)
+ AssertEqual(uuid1, uuid0)
+ }
+ })
+
+ Testing("errors we detect", func() {
+ var err error
+
+ _, err = ParseUUID("")
+ AssertEqual(err, badUUIDLengthError)
+
+ _, err = ParseUUID("---000000000000000000000000000000000")
+ AssertEqual(err, badUUIDDashCountError)
+
+ _, err = ParseUUID("----00000000000000000000000000000000")
+ AssertEqual(err, badUUIDDashPositionError)
+
+ _, err = ParseUUID("00000000-0000-0000-0000-00000000000g")
+ AssertEqual(err, hex.InvalidByteError('g'))
+
+ _, err = ParseUUID("00000000-0000-0000-0000-000000000000")
+ ErrorIf(err)
+ })
+}
+
func TestSetLoggerOutput() {
return
type entry struct {
@@ -364,4 +480,8 @@ func TestSetLoggerOutput() {
func MainTest() {
test__PBKDF()
test_scrypt()
+ test_newUUIDFrom()
+ test_NewUUID()
+ test_UUIDString()
+ test_ParseUUID()
}