diff options
author | EuAndreh <eu@euandre.org> | 2024-08-05 16:51:41 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2024-08-05 16:51:41 -0300 |
commit | 27f3f26e8ffa52aed694a0d6d17efcdd8278ba6f (patch) | |
tree | 89a881998c208e46bf0b81c95361b2e0b363b12e | |
parent | Makefile: Build with "go tool compile" and "go tool link" (diff) | |
download | gobang-27f3f26e8ffa52aed694a0d6d17efcdd8278ba6f.tar.gz gobang-27f3f26e8ffa52aed694a0d6d17efcdd8278ba6f.tar.xz |
Start using TestStart() and Testing()
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | src/gobang.go | 207 | ||||
-rw-r--r-- | tests/gobang.go | 115 | ||||
-rw-r--r-- | tests/gobang_main.go | 2 |
4 files changed, 206 insertions, 143 deletions
@@ -22,7 +22,7 @@ LDLIBS = .SUFFIXES: -.SUFFIXES: .go .a .bin +.SUFFIXES: .go .a .bin .bin-check @@ -30,14 +30,14 @@ all: include deps.mk -sources = \ - src/$(NAME).go \ - objects = \ src/$(NAME).a \ tests/$(NAME).a \ tests/$(NAME)_main.a \ +sources = \ + src/$(NAME).go \ + derived-assets = \ $(objects) \ @@ -69,8 +69,13 @@ $(objects): Makefile -check-unit: tests/$(NAME)_main.bin - ./tests/$(NAME)_main.bin +tests.bin-check = \ + tests/$(NAME)_main.bin-check \ + +$(tests.bin-check): tests/$(NAME)_main.bin + $(EXEC)$*.bin + +check-unit: $(tests.bin-check) integration-tests = \ @@ -95,8 +100,8 @@ clean: ## ensures that all installable artifacts are crafted beforehand. install: all mkdir -p \ - '$(DESTDIR)$(GOLIBDIR)' \ - '$(DESTDIR)$(SRCDIR)' \ + '$(DESTDIR)$(GOLIBDIR)' \ + '$(DESTDIR)$(SRCDIR)' \ cp src/$(NAME).a '$(DESTDIR)$(GOLIBDIR)' cp $(sources) '$(DESTDIR)$(SRCDIR)' @@ -106,8 +111,8 @@ install: all ## A dedicated test asserts that this is always true. uninstall: rm -rf \ - '$(DESTDIR)$(GOLIBDIR)'/$(NAME).a \ - '$(DESTDIR)$(SRCDIR)' \ + '$(DESTDIR)$(GOLIBDIR)'/$(NAME).a \ + '$(DESTDIR)$(SRCDIR)' \ ALWAYS: diff --git a/src/gobang.go b/src/gobang.go index 4ce13ff..4775dfc 100644 --- a/src/gobang.go +++ b/src/gobang.go @@ -19,19 +19,18 @@ import ( "strings" "sync" "syscall" - "testing" "time" ) -type LogLevel int8 +type logLevel int8 const ( - LevelNone LogLevel = 0 - LevelError LogLevel = 1 - LevelWarning LogLevel = 2 - LevelInfo LogLevel = 3 - LevelDebug LogLevel = 4 + LevelNone logLevel = 0 + LevelError logLevel = 1 + LevelWarning logLevel = 2 + LevelInfo logLevel = 3 + LevelDebug logLevel = 4 ) const lengthUUID = 16 @@ -52,7 +51,15 @@ type CopyResult struct { -const MaxInt = int((^uint(0)) >> 1) +const maxInt = int((^uint(0)) >> 1) + +const ( + scrypt_N = 32768 + scrypt_r = 8 + scrypt_p = 1 + scryptSaltMinLength = 32 + scryptDesiredLength = 32 +) @@ -62,14 +69,17 @@ const MaxInt = int((^uint(0)) >> 1) // // 52 bits of time in milliseconds since epoch // 12 bits of (fractional nanoseconds) >> 8 + var lastV7Time int64 -var timeMu sync.Mutex +var timeMutex sync.Mutex + + +// Local variables -// Global variables var ( - Level LogLevel = LevelInfo - EmitMetric bool = true - Hostname string + level logLevel = LevelInfo + emitMetric bool = true + hostname string ) @@ -104,7 +114,7 @@ var ( // // Using a higher iteration count will increase the cost of an exhaustive // search but will also make derivation proportionally slower. -func PBKDF2Key( +func _PBKDF2Key( password []byte, salt []byte, iter int, @@ -127,7 +137,7 @@ func PBKDF2Key( buf[0] = byte(block >> 24) buf[1] = byte(block >> 16) buf[2] = byte(block >> 8) - buf[3] = byte(block) + buf[3] = byte(block >> 0) prf.Write(buf[:4]) dk = prf.Sum(dk) T := dk[len(dk) - hashLen:] @@ -341,7 +351,7 @@ func smix(b []byte, r int, N int, v []uint32, xy []uint32) { // and p=1. The parameters N, r, and p should be increased as memory latency and // CPU parallelism increases; consider setting N to the highest power of 2 you // can derive within 100 milliseconds. Remember to get a good random salt. -func Scrypt( +func scrypt( password []byte, salt []byte, N int, @@ -353,35 +363,35 @@ func Scrypt( return nil, errors.New("scrypt: N must be > 1 and a power of 2") } if ((uint64(r) * uint64(p)) >= (1 << 30)) || - r > MaxInt / 128 / p || - r > MaxInt / 256 || - N > MaxInt / 128 / r { + r > maxInt / 128 / p || + r > maxInt / 256 || + N > maxInt / 128 / r { return nil, errors.New("scrypt: parameters are too large") } xy := make([]uint32, 64 * r) v := make([]uint32, 32 * N * r) - b := PBKDF2Key(password, salt, 1, p * 128 * r, sha256.New) + b := _PBKDF2Key(password, salt, 1, p * 128 * r, sha256.New) for i := 0; i < p; i++ { smix(b[i * 128 * r:], r, N, v, xy) } - return PBKDF2Key(password, b, 1, keyLen, sha256.New), nil + return _PBKDF2Key(password, b, 1, keyLen, sha256.New), nil } -func CopyData( - c chan CopyResult, - label string, - from io.Reader, - to io.WriteCloser, -) { - written, err := io.Copy(to, from) - c <- CopyResult { - Written: written, - Err: err, - Label: label, - } +func Salt() []byte { + var buf [scryptSaltMinLength]byte + _, err := io.ReadFull(rand.Reader, buf[:]) + FatalIf(err) + return buf[:] +} + +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) + FatalIf(err) + return hash } // FIXME: finish rewriting @@ -397,8 +407,8 @@ func getV7Time(nano int64) (int64, int64) { seq := (nano - (milli * nanoPerMilli)) >> 8 now := milli << (12 + seq) - timeMu.Lock() - defer timeMu.Unlock() + timeMutex.Lock() + defer timeMutex.Unlock() if now <= lastV7Time { now = lastV7Time + 1 milli = now >> 12 @@ -460,7 +470,7 @@ func (uuid UUID) ToString() string { } func Debug(message string, type_ string, args ...any) { - if Level < LevelDebug { + if level < LevelDebug { return } @@ -478,7 +488,7 @@ func Debug(message string, type_ string, args ...any) { } func Info(message string, type_ string, args ...any) { - if Level < LevelInfo { + if level < LevelInfo { return } @@ -496,7 +506,7 @@ func Info(message string, type_ string, args ...any) { } func Warning(message string, type_ string, args ...any) { - if Level < LevelWarning { + if level < LevelWarning { return } @@ -514,7 +524,7 @@ func Warning(message string, type_ string, args ...any) { } func Error(message string, type_ string, args ...any) { - if Level < LevelError { + if level < LevelError { return } @@ -532,7 +542,7 @@ func Error(message string, type_ string, args ...any) { } func Metric(type_ string, label string, args ...any) { - if !EmitMetric { + if !emitMetric { return } @@ -602,35 +612,69 @@ func MakeCounter(label string) func(...any) { } } -func ErrorIf(t *testing.T, err error) { +func ErrorIf(err error) { if err != nil { - t.Errorf("Unexpected error: %#v\n", err) + fmt.Fprintf(os.Stderr, "Unexpected error: %#v\n", err) + os.Exit(1) } } -func ErrorNil(t *testing.T, err error) { +func ErrorNil(err error) { if err == nil { - t.Errorf("Expected error, got nil\n") + fmt.Fprintf(os.Stderr, "Expected error, got nil\n") + os.Exit(1) + } +} + +func showColour() bool { + return os.Getenv("NO_COLOUR") == "" +} + +func TestStart(name string) { + fmt.Fprintf(os.Stderr, "%s:\n", name) +} + +func Testing(message string, body func()) { + if showColour() { + fmt.Fprintf(os.Stderr, "\033[0;33mtesting\033[0m: %s... ", message) + body() + fmt.Fprint(os.Stderr, "\033[0;32mOK\033[0m.\n") + } else { + fmt.Fprintf(os.Stderr, "testing: %s...", message) + body() + fmt.Fprint(os.Stderr, " OK.\n") } } -func AssertEqual(t *testing.T, given any, expected any) { +func AssertEqual(given any, expected any) { if !reflect.DeepEqual(given, expected) { - t.Errorf("given != expected\n") - t.Errorf("given: %#v\n", given) - t.Errorf("expected: %#v\n", expected) + if showColour() { + fmt.Fprintf(os.Stderr, "\033[0;31mERR\033[0m.\n") + } else { + fmt.Fprintf(os.Stderr, "ERR.\n") + } + fmt.Fprintf(os.Stderr, "given != expected\n") + fmt.Fprintf(os.Stderr, "given: %#v\n", given) + fmt.Fprintf(os.Stderr, "expected: %#v\n", expected) + os.Exit(1) } } -func AssertEqualI(t *testing.T, i int, given any, expected any) { +func AssertEqualI(i int, given any, expected any) { if !reflect.DeepEqual(given, expected) { - t.Errorf("given != expected (i = %d)\n", i) - t.Errorf("given: %#v\n", given) - t.Errorf("expected: %#v\n", expected) + if showColour() { + fmt.Fprintf(os.Stderr, "\033[0;31mERR\033[0m.\n") + } else { + fmt.Fprintf(os.Stderr, "ERR.\n") + } + fmt.Fprintf(os.Stderr, "given != expected (i = %d)\n", i) + fmt.Fprintf(os.Stderr, "given: %#v\n", given) + fmt.Fprintf(os.Stderr, "expected: %#v\n", expected) + os.Exit(1) } } -func SetLoggerOutput(w io.Writer) { +func setLoggerOutput(w io.Writer) { slog.SetDefault(slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions { AddSource: true, })).With( @@ -643,47 +687,47 @@ func SetLoggerOutput(w io.Writer) { )) } -func LevelFromString(name string) (bool, LogLevel) { - level := strings.ToUpper(name) +func levelFromString(name string) (bool, logLevel) { + label := strings.ToUpper(name) - if level == "NONE" { + if label == "NONE" { return true, LevelNone } - if level == "ERROR" { + if label == "ERROR" { return true, LevelError } - if level == "WARNING" { + if label == "WARNING" { return true, LevelWarning } - if level == "INFO" { + if label == "INFO" { return true, LevelInfo } - if level == "DEBUG" { + if label == "DEBUG" { return true, LevelDebug } - return false, Level + return false, level } -func SetLogLevel() { - ok, level := LevelFromString(os.Getenv("LOG_LEVEL")) +func setLogLevel() { + ok, envLevel := levelFromString(os.Getenv("LOG_LEVEL")) if ok { - Level = level + level = envLevel } } -func SetMetric() { +func setMetric() { if os.Getenv("NO_METRIC") != "" { - EmitMetric = false + emitMetric = false } } -func SetTraceback() { +func setTraceback() { if os.Getenv("GOTRACEBACK") == "" { debug.SetTraceback("crash") } @@ -705,21 +749,26 @@ func FatalIf(err error) { } } -func SetHostname() { - var err error - Hostname, err = os.Hostname() - FatalIf(err) +func Assert(condition bool, message string) { + if !condition { + Fatal(errors.New(message)) + } } -func Init() { - SetLoggerOutput(os.Stdout) - SetLogLevel() - SetMetric() - SetTraceback() - SetHostname() +func Unreachable() { + Assert(false, "Unreachable code was reached") } +func setHostname() { + var err error + hostname, err = os.Hostname() + FatalIf(err) +} -func Main() { - fmt.Println(NewUUID().ToString()) +func Init() { + setLoggerOutput(os.Stdout) + setLogLevel() + setMetric() + setTraceback() + setHostname() } diff --git a/tests/gobang.go b/tests/gobang.go index 3abdf6f..61168d6 100644 --- a/tests/gobang.go +++ b/tests/gobang.go @@ -9,7 +9,6 @@ import ( "fmt" "hash" "log/slog" - "testing" ) @@ -141,30 +140,29 @@ var sha256TestVectors = []pbkdfTestVector { }, } -func testHash( - t *testing.T, - h func() hash.Hash, - hashName string, - vectors []pbkdfTestVector, -) { +func testHash(h func() hash.Hash, hashName string, vectors []pbkdfTestVector) { for i, v := range vectors { - out := PBKDF2Key( + out := _PBKDF2Key( []byte(v.password), []byte(v.salt), v.iter, len(v.output), h, ) - AssertEqualI(t, i, out, v.output) + AssertEqualI(i, out, v.output) } } -func TestWithHMACSHA1(t *testing.T) { - testHash(t, sha1.New, "SHA1", sha1TestVectors) -} +func test__PBKDF() { + TestStart("_PBKDF()") + + Testing("HMAC with SHA1", func() { + testHash(sha1.New, "SHA1", sha1TestVectors) + }) -func TestWithHMACSHA256(t *testing.T) { - testHash(t, sha256.New, "SHA256", sha256TestVectors) + Testing("HMAC with SHA256", func() { + testHash(sha256.New, "SHA256", sha256TestVectors) + }) } type scryptTestVector struct { @@ -284,7 +282,7 @@ var good = []scryptTestVector { // }, } -const halfMax = MaxInt / 2 +const halfMax = maxInt / 2 var bad = []scryptTestVector { {"p", "s", 0, 1, 1, nil}, // N == 0 {"p", "s", 1, 1, 1, nil}, // N == 1 @@ -292,46 +290,53 @@ var bad = []scryptTestVector { {"p", "s", 16, halfMax, halfMax, nil}, // p * r too large } -func TestKey(t *testing.T) { - for i, v := range good { - k, err := Scrypt( - []byte(v.password), - []byte(v.salt), - v.N, - v.r, - v.p, - len(v.output), - ) - ErrorIf(t, err) - AssertEqualI(t, i, k, v.output) - } - for _, v := range bad { - _, err := Scrypt( - []byte(v.password), - []byte(v.salt), - v.N, - v.r, - v.p, - 32, - ) - ErrorNil(t, err) - } -} +func test_scrypt() { + TestStart("scrypt()") -func TestExample(t *testing.T) { - const expected = "lGnMz8io0AUkfzn6Pls1qX20Vs7PGN6sbYQ2TQgY12M=" - // 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} + Testing("good hashes", func() { + for i, v := range good { + k, err := scrypt( + []byte(v.password), + []byte(v.salt), + v.N, + v.r, + v.p, + len(v.output), + ) + ErrorIf(err) + AssertEqualI(i, k, v.output) + } + }) - dk, err := Scrypt([]byte("some password"), salt, 1<<15, 8, 1, 32) - ErrorIf(t, err) + Testing("bad hashes", func() { + for _, v := range bad { + _, err := scrypt( + []byte(v.password), + []byte(v.salt), + v.N, + v.r, + v.p, + 32, + ) + ErrorNil(err) + } + }) - given := base64.StdEncoding.EncodeToString(dk) - AssertEqual(t, given, expected) + Testing("example value", func() { + const expected = "lGnMz8io0AUkfzn6Pls1qX20Vs7PGN6sbYQ2TQgY12M=" + // 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) + ErrorIf(err) + + given := base64.StdEncoding.EncodeToString(dk) + AssertEqual(given, expected) + }) } -func TestSetLoggerOutput(t *testing.T) { +func TestSetLoggerOutput() { return type entry struct { msg string `json:"msg"` @@ -346,13 +351,17 @@ func TestSetLoggerOutput(t *testing.T) { // fmt.Println(e) err := json.Unmarshal([]byte(s), &e) if err != nil { - t.Fail() + // t.Fail() // Mmain() - Main() } if e.msg != "the message" { - t.Fail() + // t.Fail() } fmt.Println(1) // fmt.Println(e) } + +func MainTest() { + test__PBKDF() + test_scrypt() +} diff --git a/tests/gobang_main.go b/tests/gobang_main.go index d5cb7f2..2dcbdf0 100644 --- a/tests/gobang_main.go +++ b/tests/gobang_main.go @@ -3,5 +3,5 @@ package main import "gobang" func main() { - gobang.Main() + gobang.MainTest() } |