apg-go/random_test.go
Winni Neessen 203da17634
#52 and #53: Increase password generation flexibility and error handling
Added code to check if set minimum password requirements are met after generating a random password. If not, the password generation process is repeated.
This not only adds an extra layer of security but also ensures that all set criteria for the password are met.
Also enhanced error handling in functions that could return a negative integer when asked for a random number.
Changed 'minimum amount of' parameter descriptions in apg.go to avoid confusion.
2023-08-06 18:55:47 +02:00

181 lines
4.3 KiB
Go

package apg
import (
"bytes"
"strings"
"testing"
)
func TestGenerator_CoinFlip(t *testing.T) {
g := New(NewConfig())
cf := g.CoinFlip()
if cf < 0 || cf > 1 {
t.Errorf("CoinFlip failed(), expected 0 or 1, got: %d", cf)
}
}
func TestGenerator_CoinFlipBool(t *testing.T) {
g := New(NewConfig())
gt := false
for i := 0; i < 500_000; i++ {
cf := g.CoinFlipBool()
if cf {
gt = true
break
}
}
if !gt {
t.Error("CoinFlipBool likely not working, expected at least one true value in 500k tries, got none")
}
}
func TestGenerator_RandNum(t *testing.T) {
tt := []struct {
name string
v int64
max int64
min int64
sf bool
}{
{"RandNum up to 1000", 1000, 1000, 0, false},
{"RandNum should be 1", 1, 1, 0, false},
{"RandNum should fail on 1", 0, 0, 0, true},
{"RandNum should fail on negative", -1, 0, 0, true},
}
g := New(NewConfig())
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
rn, err := g.RandNum(tc.v)
if err == nil && tc.sf {
t.Errorf("random number generation was supposed to fail, but didn't, got: %d", rn)
}
if err != nil && !tc.sf {
t.Errorf("random number generation failed: %s", err)
}
if rn > tc.max {
t.Errorf("random number generation returned too big number expected below: %d, got: %d",
tc.max, rn)
}
if rn < tc.min {
t.Errorf("random number generation returned too small number, expected min: %d, got: %d",
tc.min, rn)
}
})
}
}
func TestGenerator_RandomBytes(t *testing.T) {
tt := []struct {
name string
l int64
sf bool
}{
{"1 bytes of randomness", 1, false},
{"100 bytes of randomness", 100, false},
{"1024 bytes of randomness", 1024, false},
{"4096 bytes of randomness", 4096, false},
{"-1 bytes of randomness", -1, true},
}
g := New(NewConfig())
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
rb, err := g.RandomBytes(tc.l)
if err != nil && !tc.sf {
t.Errorf("random byte generation failed: %s", err)
return
}
if tc.sf {
return
}
bl := len(rb)
if int64(bl) != tc.l {
t.Errorf("lenght of provided bytes does not match requested length: got: %d, expected: %d",
bl, tc.l)
}
if bytes.Equal(rb, make([]byte, tc.l)) {
t.Errorf("random byte generation failed. returned slice is empty")
}
})
}
}
func TestGenerator_RandomString(t *testing.T) {
g := New(NewConfig())
var l int64 = 32 * 1024
tt := []struct {
name string
cr string
nr string
sf bool
}{
{
"CharRange:AlphaLower", CharRangeAlphaLower,
CharRangeAlphaUpper + CharRangeNumeric + CharRangeSpecial, false,
},
{
"CharRange:AlphaUpper", CharRangeAlphaUpper,
CharRangeAlphaLower + CharRangeNumeric + CharRangeSpecial, false,
},
{
"CharRange:Number", CharRangeNumeric,
CharRangeAlphaLower + CharRangeAlphaUpper + CharRangeSpecial, false,
},
{
"CharRange:Special", CharRangeSpecial,
CharRangeAlphaLower + CharRangeAlphaUpper + CharRangeNumeric, false,
},
{
"CharRange:Invalid", "",
CharRangeAlphaLower + CharRangeAlphaUpper + CharRangeNumeric + CharRangeSpecial, true,
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
rs, err := g.RandomStringFromCharRange(l, tc.cr)
if err != nil && !tc.sf {
t.Errorf("RandomStringFromCharRange failed: %s", err)
}
if int64(len(rs)) != l && !tc.sf {
t.Errorf("RandomStringFromCharRange failed. Expected length: %d, got: %d", l, len(rs))
}
if strings.ContainsAny(rs, tc.nr) {
t.Errorf("RandomStringFromCharRange failed. Unexpected character found in returned string: %s", rs)
}
})
}
}
func BenchmarkGenerator_CoinFlip(b *testing.B) {
b.ReportAllocs()
g := New(NewConfig())
for i := 0; i < b.N; i++ {
_ = g.CoinFlip()
}
}
func BenchmarkGenerator_RandomBytes(b *testing.B) {
b.ReportAllocs()
g := New(NewConfig())
var l int64 = 1024
for i := 0; i < b.N; i++ {
_, err := g.RandomBytes(l)
if err != nil {
b.Errorf("failed to generate random bytes: %s", err)
return
}
}
}
func BenchmarkGenerator_RandomString(b *testing.B) {
b.ReportAllocs()
g := New(NewConfig())
cr := CharRangeAlphaUpper + CharRangeAlphaLower + CharRangeNumeric + CharRangeSpecial
for i := 0; i < b.N; i++ {
_, err := g.RandomStringFromCharRange(32, cr)
if err != nil {
b.Errorf("RandomStringFromCharRange() failed: %s", err)
}
}
}