mirror of
https://github.com/jimeh/rands.git
synced 2026-02-19 03:16:39 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
660fc4d179
|
|||
| 4642a149bb | |||
|
22fe517baa
|
|||
|
74dd8fb7e9
|
|||
|
a86282e34d
|
|||
|
0a42d1e112
|
|||
|
b59d421322
|
|||
|
164ccc497a
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.35
|
||||
version: v1.43
|
||||
env:
|
||||
VERBOSE: "true"
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
enable-all: true
|
||||
disable:
|
||||
- fieldalignment
|
||||
lll:
|
||||
line-length: 80
|
||||
tab-width: 4
|
||||
@@ -20,43 +22,52 @@ linters-settings:
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dupl
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- funlen
|
||||
- gochecknoinits
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- goerr113
|
||||
- godot
|
||||
- gofumpt
|
||||
- goimports
|
||||
- golint
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- lll
|
||||
- misspell
|
||||
- nakedret
|
||||
- nilerr
|
||||
- nlreturn
|
||||
- noctx
|
||||
- nolintlint
|
||||
- scopelint
|
||||
- prealloc
|
||||
- predeclared
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- wastedassign
|
||||
- whitespace
|
||||
|
||||
issues:
|
||||
include:
|
||||
# - EXC0002 # disable excluding of issues about comments from golint
|
||||
exclude:
|
||||
- Using the variable on range scope `tt` in function literal
|
||||
- Using the variable on range scope `tc` in function literal
|
||||
@@ -71,6 +82,12 @@ issues:
|
||||
- source: "`json:"
|
||||
linters:
|
||||
- lll
|
||||
- source: "`xml:"
|
||||
linters:
|
||||
- lll
|
||||
- source: "`yaml:"
|
||||
linters:
|
||||
- lll
|
||||
|
||||
run:
|
||||
timeout: 2m
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [0.3.0](https://github.com/jimeh/rands/compare/v0.2.0...v0.3.0) (2021-12-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **error:** export error variables ([164ccc4](https://github.com/jimeh/rands/commit/164ccc497ad9880d43b22b74d6a83c5e68d79334))
|
||||
* **randsmust:** add randsmust package ([22fe517](https://github.com/jimeh/rands/commit/22fe517baa8b6939503c0c804dd71628f7d473a3))
|
||||
|
||||
## [0.2.0](https://github.com/jimeh/rands/compare/v0.1.1...v0.2.0) (2021-03-16)
|
||||
|
||||
|
||||
|
||||
42
Makefile
42
Makefile
@@ -35,7 +35,6 @@ SHELL := env \
|
||||
#
|
||||
|
||||
TOOLS += $(TOOLDIR)/gobin
|
||||
gobin: $(TOOLDIR)/gobin
|
||||
$(TOOLDIR)/gobin:
|
||||
GO111MODULE=off go get -u github.com/myitcv/gobin
|
||||
|
||||
@@ -43,16 +42,14 @@ $(TOOLDIR)/gobin:
|
||||
define tool # 1: binary-name, 2: go-import-path
|
||||
TOOLS += $(TOOLDIR)/$(1)
|
||||
|
||||
.PHONY: $(1)
|
||||
$(1): $(TOOLDIR)/$(1)
|
||||
|
||||
$(TOOLDIR)/$(1): $(TOOLDIR)/gobin Makefile
|
||||
gobin $(V) "$(2)"
|
||||
endef
|
||||
|
||||
$(eval $(call tool,godoc,golang.org/x/tools/cmd/godoc))
|
||||
$(eval $(call tool,gofumports,mvdan.cc/gofumpt/gofumports))
|
||||
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.35))
|
||||
$(eval $(call tool,gofumpt,mvdan.cc/gofumpt))
|
||||
$(eval $(call tool,goimports,golang.org/x/tools/cmd/goimports))
|
||||
$(eval $(call tool,golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.43))
|
||||
$(eval $(call tool,gomod,github.com/Helcaraxan/gomod))
|
||||
|
||||
.PHONY: tools
|
||||
@@ -62,8 +59,8 @@ tools: $(TOOLS)
|
||||
# Development
|
||||
#
|
||||
|
||||
TEST ?= $$(go list ./... | grep -v 'vendor')
|
||||
BENCH ?= .
|
||||
TESTARGS ?=
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -72,24 +69,24 @@ clean:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test $(V) -count=1 $(TESTARGS) $(TEST)
|
||||
go test $(V) -count=1 -race $(TESTARGS) ./...
|
||||
|
||||
.PHONY: test-deps
|
||||
test-deps:
|
||||
go test all
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint
|
||||
GOGC=off golangci-lint $(V) run
|
||||
lint: $(TOOLDIR)/golangci-lint
|
||||
golangci-lint $(V) run
|
||||
|
||||
.PHONY: format
|
||||
format: gofumports
|
||||
gofumports -w .
|
||||
format: $(TOOLDIR)/goimports $(TOOLDIR)/gofumpt
|
||||
goimports -w . && gofumpt -w .
|
||||
|
||||
.SILENT: bench
|
||||
.PHONY: bench
|
||||
bench:
|
||||
go test $(V) -count=1 -bench=$(BENCH) $(TESTARGS) $(TEST)
|
||||
go test $(V) -count=1 -bench=$(BENCH) $(TESTARGS) ./...
|
||||
|
||||
#
|
||||
# Coverage
|
||||
@@ -115,16 +112,14 @@ coverage.out: $(SOURCES)
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
$(info Downloading dependencies)
|
||||
go mod download
|
||||
|
||||
.PHONY: deps-update
|
||||
deps-update:
|
||||
$(info Downloading dependencies)
|
||||
go get -u ./...
|
||||
go get -u -t ./...
|
||||
|
||||
.PHONY: deps-analyze
|
||||
deps-analyze: gomod
|
||||
deps-analyze: $(TOOLDIR)/gomod
|
||||
gomod analyze
|
||||
|
||||
.PHONY: tidy
|
||||
@@ -160,7 +155,7 @@ check-tidy:
|
||||
|
||||
# Serve docs
|
||||
.PHONY: docs
|
||||
docs: godoc
|
||||
docs: $(TOOLDIR)/godoc
|
||||
$(info serviing docs on http://127.0.0.1:6060/pkg/$(GOMODNAME)/)
|
||||
@godoc -http=127.0.0.1:6060
|
||||
|
||||
@@ -169,5 +164,14 @@ docs: godoc
|
||||
#
|
||||
|
||||
.PHONY: new-version
|
||||
new-version:
|
||||
new-version: check-npx
|
||||
npx standard-version
|
||||
|
||||
.PHONY: next-version
|
||||
next-version: check-npx
|
||||
npx standard-version --dry-run
|
||||
|
||||
.PHONY: check-npx
|
||||
check-npx:
|
||||
$(if $(shell which npx),,\
|
||||
$(error No npx found in PATH, please install NodeJS))
|
||||
|
||||
105
README.md
105
README.md
@@ -36,41 +36,94 @@ alt="GitHub issues">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
```go
|
||||
s, _ := rands.Base64(16) // => CYxqEdUB1Rzno3SyZu2g/g==
|
||||
s, _ := rands.Base64URL(16) // => zlqw9aFqcFggbk2asn3_aQ
|
||||
s, _ := rands.Hex(16) // => 956e2ec9e7f19ddd58bb935826926531
|
||||
s, _ := rands.Alphanumeric(16) // => Fvk1PkrmG5crgOjT
|
||||
s, _ := rands.Alphabetic(16) // => XEJIzcZufHkuUmRM
|
||||
s, _ := rands.Upper(16) // => UMAGAFPPNDRGLUPZ
|
||||
s, _ := rands.UpperNumeric(16) // => DF0CQS0TK9CPUO3E
|
||||
s, _ := rands.Lower(16) // => ocsmggykzrxzfwgt
|
||||
s, _ := rands.LowerNumeric(16) // => rwlv7a1p7klqffs5
|
||||
s, _ := rands.Numeric(16) // => 9403373143598295
|
||||
## [`rands`](https://pkg.go.dev/github.com/jimeh/rands) package
|
||||
|
||||
s, _ := rands.String(16, "abcdefABCDEF") // => adCDCaDEdeffeDeb
|
||||
s, _ := rands.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大")) // => 下下口九力下土夕下土八上二夕大三
|
||||
`rands` is intended for use in production code where random data generation is
|
||||
required. All functions have a error return value which should be checked.
|
||||
|
||||
s, _ := rands.DNSLabel(16) // => z0ij9o8qkbs0ru-h
|
||||
s, _ := rands.UUID() // => a62b8712-f238-43ba-a47e-333f5fffe785
|
||||
For tests there is the `randsmust` package, which has all the same functions but
|
||||
with single return values, and they panic in the event of an error.
|
||||
|
||||
n, _ := rands.Int(2147483647) // => 1334400235
|
||||
n, _ := rands.Int64(int64(9223372036854775807)) // => 8256935979116161233
|
||||
|
||||
b, _ := rands.Bytes(8) // => [0 220 137 243 135 204 34 63]
|
||||
```
|
||||
|
||||
## Import
|
||||
### Import
|
||||
|
||||
```
|
||||
import "github.com/jimeh/rands"
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```go
|
||||
s, err := rands.Base64(16) // => CYxqEdUB1Rzno3SyZu2g/g==
|
||||
s, err := rands.Base64URL(16) // => zlqw9aFqcFggbk2asn3_aQ
|
||||
s, err := rands.Hex(16) // => 956e2ec9e7f19ddd58bb935826926531
|
||||
s, err := rands.Alphanumeric(16) // => Fvk1PkrmG5crgOjT
|
||||
s, err := rands.Alphabetic(16) // => XEJIzcZufHkuUmRM
|
||||
s, err := rands.Upper(16) // => UMAGAFPPNDRGLUPZ
|
||||
s, err := rands.UpperNumeric(16) // => DF0CQS0TK9CPUO3E
|
||||
s, err := rands.Lower(16) // => ocsmggykzrxzfwgt
|
||||
s, err := rands.LowerNumeric(16) // => rwlv7a1p7klqffs5
|
||||
s, err := rands.Numeric(16) // => 9403373143598295
|
||||
|
||||
s, err := rands.String(16, "abcdefABCDEF") // => adCDCaDEdeffeDeb
|
||||
s, err := rands.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大")) // => 下下口九力下土夕下土八上二夕大三
|
||||
|
||||
s, err := rands.DNSLabel(16) // => z0ij9o8qkbs0ru-h
|
||||
s, err := rands.UUID() // => a62b8712-f238-43ba-a47e-333f5fffe785
|
||||
|
||||
n, err := rands.Int(2147483647) // => 1334400235
|
||||
n, err := rands.Int64(int64(9223372036854775807)) // => 8256935979116161233
|
||||
|
||||
b, err := rands.Bytes(8) // => [0 220 137 243 135 204 34 63]
|
||||
```
|
||||
|
||||
## [`randsmust`](https://pkg.go.dev/github.com/jimeh/rands/must) package
|
||||
|
||||
`randsmust` is specifically intended as an alternative to `rands` for use in
|
||||
tests. All functions return a single value, and panic in the event of an error.
|
||||
This makes them easy to use when building structs in test cases that need random
|
||||
data.
|
||||
|
||||
For production code, make sure to use the `rands` package and check returned
|
||||
errors.
|
||||
|
||||
### Import
|
||||
|
||||
```
|
||||
import "github.com/jimeh/rands/randsmust"
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```go
|
||||
s := randsmust.Base64(16) // => d1wm/wS6AQGduO3uaey1Cg==
|
||||
s := randsmust.Base64URL(16) // => 4pHWVcddXsL_45vhOfCdng
|
||||
s := randsmust.Hex(16) // => b5552558bc009264d129c422a666fe56
|
||||
s := randsmust.Alphanumeric(16) // => j5WkpNKmW8K701XF
|
||||
s := randsmust.Alphabetic(16) // => OXxsqfFjNLvmZqDb
|
||||
s := randsmust.Upper(16) // => AOTLYQRCVNMEPRCX
|
||||
s := randsmust.UpperNumeric(16) // => 1NTY6KATDVAXBTY2
|
||||
s := randsmust.Lower(16) // => xmftrwvurrritqfu
|
||||
s := randsmust.LowerNumeric(16) // => yszg56fzeql7pjpl
|
||||
s := randsmust.Numeric(16) // => 0761782105447226
|
||||
|
||||
s := randsmust.String(16, "abcdefABCDEF") // => dfAbBfaDDdDFDaEa
|
||||
s := randsmust.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大")) // => 十十千口三十十下九上千口七夕土口
|
||||
|
||||
s := randsmust.DNSLabel(16) // => pu31o0gqyk76x35f
|
||||
s := randsmust.UUID() // => d616c873-f3dd-4690-bcd6-ed307eec1105
|
||||
|
||||
n := randsmust.Int(2147483647) // => 1293388115
|
||||
n := randsmust.Int64(int64(9223372036854775807)) // => 6168113630900161239
|
||||
|
||||
b := randsmust.Bytes(8) // => [205 128 54 95 0 95 53 51]
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see the
|
||||
[Go Reference](https://pkg.go.dev/github.com/jimeh/rands#section-documentation)
|
||||
for documentation and examples.
|
||||
Please see the Go Reference for documentation and examples:
|
||||
|
||||
- [`rands`](https://pkg.go.dev/github.com/jimeh/rands)
|
||||
- [`randsmust`](https://pkg.go.dev/github.com/jimeh/rands/must)
|
||||
|
||||
## Benchmarks
|
||||
|
||||
@@ -79,4 +132,4 @@ https://jimeh.me/rands/dev/bench/
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/jimeh/rands/blob/master/LICENSE)
|
||||
[MIT](https://github.com/jimeh/rands/blob/main/LICENSE)
|
||||
|
||||
@@ -2,11 +2,16 @@ package rands_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/jimeh/rands"
|
||||
)
|
||||
|
||||
func ExampleBytes() {
|
||||
b, _ := rands.Bytes(8)
|
||||
fmt.Printf("%+v\n", b) // => [0 220 137 243 135 204 34 63]
|
||||
b, err := rands.Bytes(8)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%+v\n", b) // => [181 153 143 235 241 20 208 173]
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
)
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, _ := Bytes(tt.n)
|
||||
|
||||
6
ints.go
6
ints.go
@@ -6,12 +6,12 @@ import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var errInvalidMaxInt = fmt.Errorf("%w: max cannot be less than 1", errBase)
|
||||
var ErrInvalidMaxInt = fmt.Errorf("%w: max cannot be less than 1", Err)
|
||||
|
||||
// Int generates a random int ranging between 0 and max.
|
||||
func Int(max int) (int, error) {
|
||||
if max < 1 {
|
||||
return 0, errInvalidMaxInt
|
||||
return 0, ErrInvalidMaxInt
|
||||
}
|
||||
|
||||
r, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
|
||||
@@ -25,7 +25,7 @@ func Int(max int) (int, error) {
|
||||
// Int64 generates a random int64 ranging between 0 and max.
|
||||
func Int64(max int64) (int64, error) {
|
||||
if max < 1 {
|
||||
return 0, errInvalidMaxInt
|
||||
return 0, ErrInvalidMaxInt
|
||||
}
|
||||
|
||||
r, err := rand.Int(rand.Reader, big.NewInt(max))
|
||||
|
||||
@@ -2,16 +2,25 @@ package rands_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/jimeh/rands"
|
||||
)
|
||||
|
||||
func ExampleInt() {
|
||||
n, _ := rands.Int(2147483647)
|
||||
fmt.Printf("%d\n", n) // => 1334400235
|
||||
n, err := rands.Int(2147483647)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%d\n", n) // => 1908357440
|
||||
}
|
||||
|
||||
func ExampleInt64() {
|
||||
n, _ := rands.Int64(int64(9223372036854775807))
|
||||
fmt.Printf("%d\n", n) // => 8256935979116161233
|
||||
n, err := rands.Int64(int64(9223372036854775807))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("%d\n", n) // => 6530460062499341591
|
||||
}
|
||||
|
||||
31
ints_test.go
31
ints_test.go
@@ -1,7 +1,6 @@
|
||||
package rands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -16,67 +15,67 @@ var testIntCases = []struct {
|
||||
{
|
||||
name: "n=-2394345",
|
||||
max: -2394345,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-409600",
|
||||
max: -409600,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-1024",
|
||||
max: -1024,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-128",
|
||||
max: -128,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-32",
|
||||
max: -32,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-16",
|
||||
max: -16,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-8",
|
||||
max: -8,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-7",
|
||||
max: -7,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-2",
|
||||
max: -2,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-1",
|
||||
max: -1,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=0",
|
||||
max: 0,
|
||||
errIs: errInvalidMaxInt,
|
||||
errIs: ErrInvalidMaxInt,
|
||||
errStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{name: "n=1", max: 1},
|
||||
@@ -92,6 +91,8 @@ var testIntCases = []struct {
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testIntCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Int(tt.max)
|
||||
@@ -102,7 +103,7 @@ func TestInt(t *testing.T) {
|
||||
}
|
||||
|
||||
if tt.errIs != nil {
|
||||
assert.True(t, errors.Is(err, errInvalidMaxInt))
|
||||
assert.ErrorIs(t, err, tt.errIs)
|
||||
}
|
||||
|
||||
if tt.errStr != "" {
|
||||
@@ -123,6 +124,8 @@ func BenchmarkInt(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testIntCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Int64(int64(tt.max))
|
||||
@@ -133,7 +136,7 @@ func TestInt64(t *testing.T) {
|
||||
}
|
||||
|
||||
if tt.errIs != nil {
|
||||
assert.True(t, errors.Is(err, errInvalidMaxInt))
|
||||
assert.ErrorIs(t, err, tt.errIs)
|
||||
}
|
||||
|
||||
if tt.errStr != "" {
|
||||
|
||||
9
rands.go
9
rands.go
@@ -4,8 +4,15 @@
|
||||
//
|
||||
// All functions which produce strings from a alphabet of characters uses
|
||||
// rand.Int() to ensure a uniform distribution of all possible values.
|
||||
//
|
||||
// rands is intended for use in production code where random data generation is
|
||||
// required. All functions have a error return value, which should be
|
||||
// checked.
|
||||
//
|
||||
// For tests there is the randsmust package, which has all the same functions
|
||||
// but with single return values, and they panic in the event of an error.
|
||||
package rands
|
||||
|
||||
import "errors"
|
||||
|
||||
var errBase = errors.New("rands")
|
||||
var Err = errors.New("rands")
|
||||
|
||||
13
randsmust/bytes.go
Normal file
13
randsmust/bytes.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package randsmust
|
||||
|
||||
import "github.com/jimeh/rands"
|
||||
|
||||
// Bytes generates a byte slice of n number of random bytes.
|
||||
func Bytes(n int) []byte {
|
||||
r, err := rands.Bytes(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
12
randsmust/bytes_example_test.go
Normal file
12
randsmust/bytes_example_test.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package randsmust_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jimeh/rands/randsmust"
|
||||
)
|
||||
|
||||
func ExampleBytes() {
|
||||
b := randsmust.Bytes(8)
|
||||
fmt.Printf("%+v\n", b) // => [6 99 106 54 163 188 28 152]
|
||||
}
|
||||
19
randsmust/bytes_test.go
Normal file
19
randsmust/bytes_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package randsmust
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Bytes(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
})
|
||||
}
|
||||
}
|
||||
23
randsmust/ints.go
Normal file
23
randsmust/ints.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package randsmust
|
||||
|
||||
import "github.com/jimeh/rands"
|
||||
|
||||
// Int generates a random int ranging between 0 and max.
|
||||
func Int(max int) int {
|
||||
r, err := rands.Int(max)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Int64 generates a random int64 ranging between 0 and max.
|
||||
func Int64(max int64) int64 {
|
||||
r, err := rands.Int64(max)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
17
randsmust/ints_example_test.go
Normal file
17
randsmust/ints_example_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package randsmust_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jimeh/rands/randsmust"
|
||||
)
|
||||
|
||||
func ExampleInt() {
|
||||
n := randsmust.Int(2147483647)
|
||||
fmt.Printf("%d\n", n) // => 1616989970
|
||||
}
|
||||
|
||||
func ExampleInt64() {
|
||||
n := randsmust.Int64(int64(9223372036854775807))
|
||||
fmt.Printf("%d\n", n) // => 1599573251306894157
|
||||
}
|
||||
144
randsmust/ints_test.go
Normal file
144
randsmust/ints_test.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package randsmust
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jimeh/rands"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var testIntCases = []struct {
|
||||
name string
|
||||
max int
|
||||
panicErrIs error
|
||||
panicStr string
|
||||
}{
|
||||
{
|
||||
name: "n=-2394345",
|
||||
max: -2394345,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-409600",
|
||||
max: -409600,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-1024",
|
||||
max: -1024,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-128",
|
||||
max: -128,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-32",
|
||||
max: -32,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-16",
|
||||
max: -16,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-8",
|
||||
max: -8,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-7",
|
||||
max: -7,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-2",
|
||||
max: -2,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=-1",
|
||||
max: -1,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{
|
||||
name: "n=0",
|
||||
max: 0,
|
||||
panicErrIs: rands.ErrInvalidMaxInt,
|
||||
panicStr: "rands: max cannot be less than 1",
|
||||
},
|
||||
{name: "n=1", max: 1},
|
||||
{name: "n=2", max: 2},
|
||||
{name: "n=7", max: 7},
|
||||
{name: "n=8", max: 8},
|
||||
{name: "n=16", max: 16},
|
||||
{name: "n=32", max: 32},
|
||||
{name: "n=128", max: 128},
|
||||
{name: "n=1024", max: 1024},
|
||||
{name: "n=409600", max: 409600},
|
||||
{name: "n=2394345", max: 2394345},
|
||||
}
|
||||
|
||||
func TestInt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testIntCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var got int
|
||||
p := recoverPanic(func() {
|
||||
got = Int(tt.max)
|
||||
})
|
||||
|
||||
if tt.panicErrIs == nil || tt.panicStr == "" {
|
||||
assert.GreaterOrEqual(t, got, 0)
|
||||
assert.LessOrEqual(t, got, tt.max)
|
||||
}
|
||||
|
||||
if tt.panicErrIs != nil {
|
||||
assert.ErrorIs(t, p.(error), tt.panicErrIs)
|
||||
}
|
||||
|
||||
if tt.panicStr != "" {
|
||||
assert.EqualError(t, p.(error), tt.panicStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range testIntCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var got int64
|
||||
p := recoverPanic(func() {
|
||||
got = Int64(int64(tt.max))
|
||||
})
|
||||
|
||||
if tt.panicErrIs == nil || tt.panicStr == "" {
|
||||
assert.GreaterOrEqual(t, got, int64(0))
|
||||
assert.LessOrEqual(t, got, int64(tt.max))
|
||||
}
|
||||
|
||||
if tt.panicErrIs != nil {
|
||||
assert.ErrorIs(t, p.(error), tt.panicErrIs)
|
||||
}
|
||||
|
||||
if tt.panicStr != "" {
|
||||
assert.EqualError(t, p.(error), tt.panicStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
15
randsmust/randsmust.go
Normal file
15
randsmust/randsmust.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Package randsmust provides a suite of functions that use crypto/rand to
|
||||
// generate cryptographically secure random strings in various formats, as well
|
||||
// as ints and bytes.
|
||||
//
|
||||
// All functions which produce strings from a alphabet of characters uses
|
||||
// rand.Int() to ensure a uniform distribution of all possible values.
|
||||
//
|
||||
// randsmust is specifically intended as an alternative to rands for use in
|
||||
// tests. All functions return a single value, and panic in the event of an
|
||||
// error. This makes them easy to use when building structs in test cases that
|
||||
// need random data.
|
||||
//
|
||||
// For production code, make sure to use the rands package and check returned
|
||||
// errors.
|
||||
package randsmust
|
||||
30
randsmust/randsmust_test.go
Normal file
30
randsmust/randsmust_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package randsmust
|
||||
|
||||
var testCases = []struct {
|
||||
name string
|
||||
n int
|
||||
}{
|
||||
{name: "n=0", n: 0},
|
||||
{name: "n=1", n: 1},
|
||||
{name: "n=2", n: 2},
|
||||
{name: "n=7", n: 7},
|
||||
{name: "n=8", n: 8},
|
||||
{name: "n=16", n: 16},
|
||||
{name: "n=32", n: 32},
|
||||
{name: "n=128", n: 128},
|
||||
{name: "n=1024", n: 1024},
|
||||
{name: "n=409600", n: 409600},
|
||||
{name: "n=2394345", n: 2394345},
|
||||
}
|
||||
|
||||
func recoverPanic(f func()) (p interface{}) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
p = r
|
||||
}
|
||||
}()
|
||||
|
||||
f()
|
||||
|
||||
return
|
||||
}
|
||||
192
randsmust/strings.go
Normal file
192
randsmust/strings.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package randsmust
|
||||
|
||||
import (
|
||||
"github.com/jimeh/rands"
|
||||
)
|
||||
|
||||
// Base64 generates a random base64 encoded string of n number of bytes.
|
||||
//
|
||||
// Length of the returned string is about one third greater than the value of n,
|
||||
// and it may contain characters A-Z, a-z, 0-9, "+", "/", and "=".
|
||||
func Base64(n int) string {
|
||||
r, err := rands.Base64(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Base64URL generates a URL-safe un-padded random base64 encoded string of n
|
||||
// number of bytes.
|
||||
//
|
||||
// Length of the returned string is about one third greater than the value of n,
|
||||
// and it may contain characters A-Z, a-z, 0-9, "-", and "_".
|
||||
func Base64URL(n int) string {
|
||||
r, err := rands.Base64URL(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Hex generates a random hexadecimal encoded string of n number of bytes.
|
||||
//
|
||||
// Length of the returned string is twice the value of n, and it may contain
|
||||
// characters 0-9 and a-f.
|
||||
func Hex(n int) string {
|
||||
r, err := rands.Hex(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Alphanumeric generates a random alphanumeric string of n length.
|
||||
//
|
||||
// The returned string may contain A-Z, a-z, and 0-9.
|
||||
func Alphanumeric(n int) string {
|
||||
r, err := rands.Alphanumeric(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Alphabetic generates a random alphabetic string of n length.
|
||||
//
|
||||
// The returned string may contain A-Z, and a-z.
|
||||
func Alphabetic(n int) string {
|
||||
r, err := rands.Alphabetic(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Numeric generates a random numeric string of n length.
|
||||
//
|
||||
// The returned string may contain 0-9.
|
||||
func Numeric(n int) string {
|
||||
r, err := rands.Numeric(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Upper generates a random uppercase alphabetic string of n length.
|
||||
//
|
||||
// The returned string may contain A-Z.
|
||||
func Upper(n int) string {
|
||||
r, err := rands.Upper(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// UpperNumeric generates a random uppercase alphanumeric string of n length.
|
||||
//
|
||||
// The returned string may contain A-Z and 0-9.
|
||||
func UpperNumeric(n int) string {
|
||||
r, err := rands.UpperNumeric(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Lower generates a random lowercase alphabetic string of n length.
|
||||
//
|
||||
// The returned string may contain a-z.
|
||||
func Lower(n int) string {
|
||||
r, err := rands.Lower(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// LowerNumeric generates a random lowercase alphanumeric string of n length.
|
||||
//
|
||||
// The returned string may contain A-Z and 0-9.
|
||||
func LowerNumeric(n int) string {
|
||||
r, err := rands.LowerNumeric(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// String generates a random string of n length using the given ASCII alphabet.
|
||||
//
|
||||
// The specified alphabet determines what characters are used in the returned
|
||||
// random string. The alphabet can only contain ASCII characters, use
|
||||
// UnicodeString() if you need a alphabet with Unicode characters.
|
||||
func String(n int, alphabet string) string {
|
||||
r, err := rands.String(n, alphabet)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// UnicodeString generates a random string of n length using the given Unicode
|
||||
// alphabet.
|
||||
//
|
||||
// The specified alphabet determines what characters are used in the returned
|
||||
// random string. The length of the returned string will be n or greater
|
||||
// depending on the byte-length of characters which were randomly selected from
|
||||
// the alphabet.
|
||||
func UnicodeString(n int, alphabet []rune) string {
|
||||
r, err := rands.UnicodeString(n, alphabet)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// DNSLabel returns a random string of n length in a DNS label compliant format
|
||||
// as defined in RFC 1035, section 2.3.1.
|
||||
//
|
||||
// It also adheres to RFC 5891, section 4.2.3.1.
|
||||
//
|
||||
// In summary, the generated random string will:
|
||||
//
|
||||
// - be between 1 and 63 characters in length, other n values returns a error
|
||||
// - first character will be one of a-z
|
||||
// - last character will be one of a-z or 0-9
|
||||
// - in-between first and last characters consist of a-z, 0-9, or "-"
|
||||
// - potentially contain two or more consecutive "-", except the 3rd and 4th
|
||||
// characters, as that would violate RFC 5891, section 4.2.3.1.
|
||||
func DNSLabel(n int) string {
|
||||
r, err := rands.DNSLabel(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// UUID returns a random UUID v4 in string format as defined by RFC 4122,
|
||||
// section 4.4.
|
||||
func UUID() string {
|
||||
r, err := rands.UUID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
77
randsmust/strings_example_test.go
Normal file
77
randsmust/strings_example_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package randsmust_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jimeh/rands/randsmust"
|
||||
)
|
||||
|
||||
func ExampleBase64() {
|
||||
s := randsmust.Base64(16)
|
||||
fmt.Println(s) // => rGnZOxJunCd5h+piBpOfDA==
|
||||
}
|
||||
|
||||
func ExampleBase64URL() {
|
||||
s := randsmust.Base64URL(16)
|
||||
fmt.Println(s) // => NlXKmutou2knLU8q7Hlp5Q
|
||||
}
|
||||
|
||||
func ExampleHex() {
|
||||
s := randsmust.Hex(16)
|
||||
fmt.Println(s) // => 1013ec67a802be177d3e37f46951e97f
|
||||
}
|
||||
|
||||
func ExampleAlphanumeric() {
|
||||
s := randsmust.Alphanumeric(16)
|
||||
fmt.Println(s) // => mjT119HdPslVfvUE
|
||||
}
|
||||
|
||||
func ExampleAlphabetic() {
|
||||
s := randsmust.Alphabetic(16)
|
||||
fmt.Println(s) // => RLaRaTVqcrxvNkiz
|
||||
}
|
||||
|
||||
func ExampleUpper() {
|
||||
s := randsmust.Upper(16)
|
||||
fmt.Println(s) // => CANJDLMHANPQNXUE
|
||||
}
|
||||
|
||||
func ExampleUpperNumeric() {
|
||||
s := randsmust.UpperNumeric(16)
|
||||
fmt.Println(s) // => EERZHC96KOIRU9DM
|
||||
}
|
||||
|
||||
func ExampleLower() {
|
||||
s := randsmust.Lower(16)
|
||||
fmt.Println(s) // => aoybqdwigyezucjy
|
||||
}
|
||||
|
||||
func ExampleLowerNumeric() {
|
||||
s := randsmust.LowerNumeric(16)
|
||||
fmt.Println(s) // => hs8l2l0750med3g2
|
||||
}
|
||||
|
||||
func ExampleNumeric() {
|
||||
s := randsmust.Numeric(16)
|
||||
fmt.Println(s) // => 3126402104379869
|
||||
}
|
||||
|
||||
func ExampleString() {
|
||||
s := randsmust.String(16, "abcdefABCDEF")
|
||||
fmt.Println(s) // => cbdCAbABECaADcaB
|
||||
}
|
||||
|
||||
func ExampleUnicodeString() {
|
||||
s := randsmust.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大"))
|
||||
fmt.Println(s) // => 下夕七下千千力入八三力夕千三土七
|
||||
}
|
||||
|
||||
func ExampleDNSLabel() {
|
||||
s := randsmust.DNSLabel(16)
|
||||
fmt.Println(s) // => urqkt-remuwz5083
|
||||
}
|
||||
|
||||
func ExampleUUID() {
|
||||
s := randsmust.UUID()
|
||||
fmt.Println(s) // => 5baa35a6-9a46-49b4-91d0-9530173e118d
|
||||
}
|
||||
558
randsmust/strings_test.go
Normal file
558
randsmust/strings_test.go
Normal file
@@ -0,0 +1,558 @@
|
||||
package randsmust
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jimeh/rands"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHex(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "0123456789abcdef"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Hex(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n*2)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
|
||||
"0123456789+/="
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Base64(tt.n)
|
||||
|
||||
b, err := base64.StdEncoding.DecodeString(got)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, b, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBase64URL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
|
||||
"0123456789-_"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Base64URL(tt.n)
|
||||
|
||||
b, err := base64.RawURLEncoding.DecodeString(got)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, b, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlphanumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Alphanumeric(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlphabetic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Alphabetic(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Numeric(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpper(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Upper(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpperNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := UpperNumeric(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLower(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Lower(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLowerNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := LowerNumeric(tt.n)
|
||||
|
||||
assert.Len(t, got, tt.n)
|
||||
assertAllowedChars(t, allowed, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var stringTestCases = []struct {
|
||||
name string
|
||||
n int
|
||||
alphabet string
|
||||
panicErrIs error
|
||||
panicStr string
|
||||
}{
|
||||
{
|
||||
name: "greek",
|
||||
n: 32,
|
||||
alphabet: "αβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩ" +
|
||||
"άίόύώέϊϋΐΰΆΈΌΏΎΊ",
|
||||
panicErrIs: rands.ErrNonASCIIAlphabet,
|
||||
panicStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
name: "chinese",
|
||||
n: 32,
|
||||
alphabet: "的一是不了人我在有他这为之大来以个中上们到说国和地也子" +
|
||||
"时道出而要于就下得可你年生",
|
||||
panicErrIs: rands.ErrNonASCIIAlphabet,
|
||||
panicStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
name: "japanese",
|
||||
n: 32,
|
||||
alphabet: "一九七二人入八力十下三千上口土夕大女子小山川五天中六円" +
|
||||
"手文日月木水火犬王正出本右四",
|
||||
panicErrIs: rands.ErrNonASCIIAlphabet,
|
||||
panicStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
name: "n=0",
|
||||
n: 0,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=1",
|
||||
n: 1,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=2",
|
||||
n: 2,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=7",
|
||||
n: 7,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=8",
|
||||
n: 8,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=16",
|
||||
n: 16,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=32",
|
||||
n: 32,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=128",
|
||||
n: 128,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=1024",
|
||||
n: 1024,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=409600",
|
||||
n: 409600,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "n=2394345",
|
||||
n: 2394345,
|
||||
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-",
|
||||
},
|
||||
{
|
||||
name: "uppercase",
|
||||
n: 16,
|
||||
alphabet: "ABCDEFGHJKMNPRSTUVWXYZ",
|
||||
},
|
||||
{
|
||||
name: "lowercase",
|
||||
n: 16,
|
||||
alphabet: "abcdefghjkmnprstuvwxyz",
|
||||
},
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range stringTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var got string
|
||||
p := recoverPanic(func() {
|
||||
got = String(tt.n, tt.alphabet)
|
||||
})
|
||||
|
||||
if tt.panicErrIs == nil || tt.panicStr == "" {
|
||||
assert.Len(t, []rune(got), tt.n)
|
||||
assertAllowedChars(t, tt.alphabet, got)
|
||||
}
|
||||
|
||||
if tt.panicErrIs != nil {
|
||||
assert.ErrorIs(t, p.(error), tt.panicErrIs)
|
||||
}
|
||||
|
||||
if tt.panicStr != "" {
|
||||
assert.EqualError(t, p.(error), tt.panicStr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var unicodeStringTestCases = []struct {
|
||||
name string
|
||||
n int
|
||||
alphabet string
|
||||
}{
|
||||
{
|
||||
name: "n=0",
|
||||
n: 0,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=1",
|
||||
n: 1,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=2",
|
||||
n: 2,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=7",
|
||||
n: 7,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=8",
|
||||
n: 8,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=16",
|
||||
n: 16,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=32",
|
||||
n: 32,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=128",
|
||||
n: 128,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=1024",
|
||||
n: 1024,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=409600",
|
||||
n: 409600,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "n=2394345",
|
||||
n: 2394345,
|
||||
alphabet: "αβγδεζηθικλμν时道出而要于就下得可你年" +
|
||||
"手文日月木水火犬王正出本右",
|
||||
},
|
||||
{
|
||||
name: "latin",
|
||||
n: 32,
|
||||
alphabet: "ABCDEFGHJKMNPRSTUVWXYZabcdefghjkmnprstuvwxyz",
|
||||
},
|
||||
{
|
||||
name: "greek",
|
||||
n: 32,
|
||||
alphabet: "αβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩ" +
|
||||
"άίόύώέϊϋΐΰΆΈΌΏΎΊ",
|
||||
},
|
||||
{
|
||||
name: "chinese",
|
||||
n: 32,
|
||||
alphabet: "的一是不了人我在有他这为之大来以个中上们到说国和地也子" +
|
||||
"时道出而要于就下得可你年生",
|
||||
},
|
||||
{
|
||||
name: "japanese",
|
||||
n: 32,
|
||||
alphabet: "一九七二人入八力十下三千上口土夕大女子小山川五天中六円" +
|
||||
"手文日月木水火犬王正出本右四",
|
||||
},
|
||||
}
|
||||
|
||||
func TestUnicodeString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range unicodeStringTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := UnicodeString(tt.n, []rune(tt.alphabet))
|
||||
|
||||
assert.Len(t, []rune(got), tt.n)
|
||||
assertAllowedChars(t, tt.alphabet, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var dnsLabelTestCases = []struct {
|
||||
name string
|
||||
n int
|
||||
panicErrIs error
|
||||
panicStr string
|
||||
}{
|
||||
{
|
||||
name: "n=-128",
|
||||
n: -128,
|
||||
panicErrIs: rands.ErrDNSLabelLength,
|
||||
panicStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
{
|
||||
name: "n=0",
|
||||
n: 0,
|
||||
panicErrIs: rands.ErrDNSLabelLength,
|
||||
panicStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
{name: "n=1", n: 1},
|
||||
{name: "n=2", n: 2},
|
||||
{name: "n=3", n: 3},
|
||||
{name: "n=4", n: 4},
|
||||
{name: "n=5", n: 5},
|
||||
{name: "n=6", n: 6},
|
||||
{name: "n=7", n: 7},
|
||||
{name: "n=8", n: 8},
|
||||
{name: "n=16", n: 16},
|
||||
{name: "n=32", n: 32},
|
||||
{name: "n=63", n: 63},
|
||||
{
|
||||
name: "n=64",
|
||||
n: 64,
|
||||
panicErrIs: rands.ErrDNSLabelLength,
|
||||
panicStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
{
|
||||
name: "n=128",
|
||||
n: 128,
|
||||
panicErrIs: rands.ErrDNSLabelLength,
|
||||
panicStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
}
|
||||
|
||||
func TestDNSLabel(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range dnsLabelTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// generate lots of labels to increase the chances of catching any
|
||||
// obscure bugs
|
||||
for i := 0; i < 10000; i++ {
|
||||
var got string
|
||||
p := recoverPanic(func() {
|
||||
got = DNSLabel(tt.n)
|
||||
})
|
||||
|
||||
if tt.panicErrIs == nil || tt.panicStr == "" {
|
||||
require.Len(t, got, tt.n)
|
||||
asserDNSLabel(t, got)
|
||||
}
|
||||
|
||||
if tt.panicErrIs != nil {
|
||||
require.ErrorIs(t, p.(error), tt.panicErrIs)
|
||||
}
|
||||
|
||||
if tt.panicStr != "" {
|
||||
require.EqualError(t, p.(error), tt.panicStr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := regexp.MustCompile(
|
||||
`^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$`,
|
||||
)
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
got := UUID()
|
||||
require.Regexp(t, m, got)
|
||||
|
||||
raw := strings.ReplaceAll(got, "-", "")
|
||||
b := make([]byte, 16)
|
||||
_, err := hex.Decode(b, []byte(raw))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 4, int(b[6]>>4), "version is not 4")
|
||||
require.Equal(t, byte(0x80), b[8]&0xc0,
|
||||
"variant is not RFC 4122",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
var (
|
||||
dnsLabelHeadRx = regexp.MustCompile(`^[a-z]$`)
|
||||
dnsLabelBodyRx = regexp.MustCompile(`^[a-z0-9-]+$`)
|
||||
dnsLabelTailRx = regexp.MustCompile(`^[a-z0-9]$`)
|
||||
)
|
||||
|
||||
func asserDNSLabel(t *testing.T, label string) {
|
||||
require.LessOrEqualf(t, len(label), 63,
|
||||
`DNS label "%s" is longer than 63 characters`, label,
|
||||
)
|
||||
|
||||
require.GreaterOrEqualf(t, len(label), 1,
|
||||
`DNS label "%s" is shorter than 1 character`, label,
|
||||
)
|
||||
|
||||
if len(label) >= 1 {
|
||||
require.Regexpf(t, dnsLabelHeadRx, string(label[0]),
|
||||
`DNS label "%s" must start with a-z`, label,
|
||||
)
|
||||
}
|
||||
if len(label) >= 2 {
|
||||
require.Regexpf(t, dnsLabelTailRx, string(label[len(label)-1]),
|
||||
`DNS label "%s" must end with a-z0-9`, label,
|
||||
)
|
||||
}
|
||||
if len(label) >= 3 {
|
||||
require.Regexpf(t, dnsLabelBodyRx, label[1:len(label)-1],
|
||||
`DNS label "%s" body must only contain a-z0-9-`, label)
|
||||
}
|
||||
if len(label) >= 4 {
|
||||
require.NotEqualf(t, "--", label[2:4],
|
||||
`DNS label "%s" cannot contain "--" as 3rd and 4th char`, label,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func assertAllowedChars(t *testing.T, allowed string, s string) {
|
||||
invalid := ""
|
||||
for _, c := range s {
|
||||
if !strings.Contains(allowed, string(c)) &&
|
||||
!strings.Contains(invalid, string(c)) {
|
||||
invalid += string(c)
|
||||
}
|
||||
}
|
||||
|
||||
assert.Truef(
|
||||
t, len(invalid) == 0, "string contains invalid chars: %s", invalid,
|
||||
)
|
||||
}
|
||||
12
strings.go
12
strings.go
@@ -22,12 +22,12 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
errNonASCIIAlphabet = fmt.Errorf(
|
||||
"%w: alphabet contains non-ASCII characters", errBase,
|
||||
ErrNonASCIIAlphabet = fmt.Errorf(
|
||||
"%w: alphabet contains non-ASCII characters", Err,
|
||||
)
|
||||
|
||||
errDNSLabelLength = fmt.Errorf(
|
||||
"%w: DNS labels must be between 1 and 63 characters in length", errBase,
|
||||
ErrDNSLabelLength = fmt.Errorf(
|
||||
"%w: DNS labels must be between 1 and 63 characters in length", Err,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -127,7 +127,7 @@ func LowerNumeric(n int) (string, error) {
|
||||
// UnicodeString() if you need a alphabet with Unicode characters.
|
||||
func String(n int, alphabet string) (string, error) {
|
||||
if !isASCII(alphabet) {
|
||||
return "", errNonASCIIAlphabet
|
||||
return "", ErrNonASCIIAlphabet
|
||||
}
|
||||
|
||||
l := big.NewInt(int64(len(alphabet)))
|
||||
@@ -180,7 +180,7 @@ func UnicodeString(n int, alphabet []rune) (string, error) {
|
||||
func DNSLabel(n int) (string, error) {
|
||||
switch {
|
||||
case n < 1 || n > 63:
|
||||
return "", errDNSLabelLength
|
||||
return "", ErrDNSLabelLength
|
||||
case n == 1:
|
||||
return String(1, lowerChars)
|
||||
default:
|
||||
|
||||
@@ -2,76 +2,133 @@ package rands_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/jimeh/rands"
|
||||
)
|
||||
|
||||
func ExampleBase64() {
|
||||
s, _ := rands.Base64(16)
|
||||
fmt.Println(s) // => CYxqEdUB1Rzno3SyZu2g/g==
|
||||
s, err := rands.Base64(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => nYQLhIYTqh8oH/W4hZuXMQ==
|
||||
}
|
||||
|
||||
func ExampleBase64URL() {
|
||||
s, _ := rands.Base64URL(16)
|
||||
fmt.Println(s) // => zlqw9aFqcFggbk2asn3_aQ
|
||||
s, err := rands.Base64URL(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => zI_zrc1l0uPT4MxncR6e5w
|
||||
}
|
||||
|
||||
func ExampleHex() {
|
||||
s, _ := rands.Hex(16)
|
||||
fmt.Println(s) // => 956e2ec9e7f19ddd58bb935826926531
|
||||
s, err := rands.Hex(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => b59e8977a13f3c030bd2ea1002ec8081
|
||||
}
|
||||
|
||||
func ExampleAlphanumeric() {
|
||||
s, _ := rands.Alphanumeric(16)
|
||||
fmt.Println(s) // => Fvk1PkrmG5crgOjT
|
||||
s, err := rands.Alphanumeric(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => EgPieCBO7MuWhHtj
|
||||
}
|
||||
|
||||
func ExampleAlphabetic() {
|
||||
s, _ := rands.Alphabetic(16)
|
||||
fmt.Println(s) // => XEJIzcZufHkuUmRM
|
||||
s, err := rands.Alphabetic(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => VzcovEqvMRBWUtQC
|
||||
}
|
||||
|
||||
func ExampleUpper() {
|
||||
s, _ := rands.Upper(16)
|
||||
fmt.Println(s) // => UMAGAFPPNDRGLUPZ
|
||||
s, err := rands.Upper(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => MCZEGPWGYKNUEDCK
|
||||
}
|
||||
|
||||
func ExampleUpperNumeric() {
|
||||
s, _ := rands.UpperNumeric(16)
|
||||
fmt.Println(s) // => DF0CQS0TK9CPUO3E
|
||||
s, err := rands.UpperNumeric(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => 6LLPBBUW77B26X2X
|
||||
}
|
||||
|
||||
func ExampleLower() {
|
||||
s, _ := rands.Lower(16)
|
||||
fmt.Println(s) // => ocsmggykzrxzfwgt
|
||||
s, err := rands.Lower(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => dhoqhrqljadsztaa
|
||||
}
|
||||
|
||||
func ExampleLowerNumeric() {
|
||||
s, _ := rands.LowerNumeric(16)
|
||||
fmt.Println(s) // => rwlv7a1p7klqffs5
|
||||
s, err := rands.LowerNumeric(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => th1z1b1d24l5h8pu
|
||||
}
|
||||
|
||||
func ExampleNumeric() {
|
||||
s, _ := rands.Numeric(16)
|
||||
fmt.Println(s) // => 9403373143598295
|
||||
s, err := rands.Numeric(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => 3378802228987741
|
||||
}
|
||||
|
||||
func ExampleString() {
|
||||
s, _ := rands.String(16, "abcdefABCDEF")
|
||||
fmt.Println(s) // => adCDCaDEdeffeDeb
|
||||
s, err := rands.String(16, "abcdefABCDEF")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => BAFffADaadeeacfa
|
||||
}
|
||||
|
||||
func ExampleUnicodeString() {
|
||||
s, _ := rands.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大"))
|
||||
fmt.Println(s) // => 下下口九力下土夕下土八上二夕大三
|
||||
s, err := rands.UnicodeString(16, []rune("九七二人入八力十下三千上口土夕大"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => 八三口上土土七入力夕人力下三上力
|
||||
}
|
||||
|
||||
func ExampleDNSLabel() {
|
||||
s, _ := rands.DNSLabel(16)
|
||||
fmt.Println(s) // => z0ij9o8qkbs0ru-h
|
||||
s, err := rands.DNSLabel(16)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => ab-sbh5q0gfb6sqo
|
||||
}
|
||||
|
||||
func ExampleUUID() {
|
||||
s, _ := rands.UUID()
|
||||
fmt.Println(s) // => a62b8712-f238-43ba-a47e-333f5fffe785
|
||||
s, err := rands.UUID()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(s) // => 6a1c4f65-d5d6-4a28-aa51-eaa94fa7ad4a
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package rands
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -13,6 +12,8 @@ import (
|
||||
)
|
||||
|
||||
func TestHex(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "0123456789abcdef"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -36,6 +37,8 @@ func BenchmarkHex(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestBase64(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
|
||||
"0123456789+/="
|
||||
|
||||
@@ -63,6 +66,8 @@ func BenchmarkBase64(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestBase64URL(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
|
||||
"0123456789-_"
|
||||
|
||||
@@ -90,6 +95,8 @@ func BenchmarkBase64URL(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestAlphanumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -113,6 +120,8 @@ func BenchmarkAlphanumeric(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestAlphabetic(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -136,6 +145,8 @@ func BenchmarkAlphabetic(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -159,6 +170,8 @@ func BenchmarkNumeric(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestUpper(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -182,6 +195,8 @@ func BenchmarkUpper(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestUpperNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -205,6 +220,8 @@ func BenchmarkUpperNumeric(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestLower(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -228,6 +245,8 @@ func BenchmarkLower(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestLowerNumeric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
allowed := "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
for _, tt := range testCases {
|
||||
@@ -262,7 +281,7 @@ var stringTestCases = []struct {
|
||||
n: 32,
|
||||
alphabet: "αβγδεζηθικλμνξοπρστυφχψωςΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΩ" +
|
||||
"άίόύώέϊϋΐΰΆΈΌΏΎΊ",
|
||||
errIs: errNonASCIIAlphabet,
|
||||
errIs: ErrNonASCIIAlphabet,
|
||||
errStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
@@ -270,7 +289,7 @@ var stringTestCases = []struct {
|
||||
n: 32,
|
||||
alphabet: "的一是不了人我在有他这为之大来以个中上们到说国和地也子" +
|
||||
"时道出而要于就下得可你年生",
|
||||
errIs: errNonASCIIAlphabet,
|
||||
errIs: ErrNonASCIIAlphabet,
|
||||
errStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
@@ -278,7 +297,7 @@ var stringTestCases = []struct {
|
||||
n: 32,
|
||||
alphabet: "一九七二人入八力十下三千上口土夕大女子小山川五天中六円" +
|
||||
"手文日月木水火犬王正出本右四",
|
||||
errIs: errNonASCIIAlphabet,
|
||||
errIs: ErrNonASCIIAlphabet,
|
||||
errStr: "rands: alphabet contains non-ASCII characters",
|
||||
},
|
||||
{
|
||||
@@ -349,6 +368,8 @@ var stringTestCases = []struct {
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range stringTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := String(tt.n, tt.alphabet)
|
||||
@@ -359,7 +380,7 @@ func TestString(t *testing.T) {
|
||||
}
|
||||
|
||||
if tt.errIs != nil {
|
||||
assert.True(t, errors.Is(err, errNonASCIIAlphabet))
|
||||
assert.ErrorIs(t, err, tt.errIs)
|
||||
}
|
||||
|
||||
if tt.errStr != "" {
|
||||
@@ -476,6 +497,8 @@ var unicodeStringTestCases = []struct {
|
||||
}
|
||||
|
||||
func TestUnicodeString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range unicodeStringTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, _ := UnicodeString(tt.n, []rune(tt.alphabet))
|
||||
@@ -507,14 +530,14 @@ var dnsLabelTestCases = []struct {
|
||||
{
|
||||
name: "n=-128",
|
||||
n: -128,
|
||||
errIs: errDNSLabelLength,
|
||||
errIs: ErrDNSLabelLength,
|
||||
errStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
{
|
||||
name: "n=0",
|
||||
n: 0,
|
||||
errIs: errDNSLabelLength,
|
||||
errIs: ErrDNSLabelLength,
|
||||
errStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
@@ -532,20 +555,22 @@ var dnsLabelTestCases = []struct {
|
||||
{
|
||||
name: "n=64",
|
||||
n: 64,
|
||||
errIs: errDNSLabelLength,
|
||||
errIs: ErrDNSLabelLength,
|
||||
errStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
{
|
||||
name: "n=128",
|
||||
n: 128,
|
||||
errIs: errDNSLabelLength,
|
||||
errIs: ErrDNSLabelLength,
|
||||
errStr: "rands: DNS labels must be between 1 and 63 characters " +
|
||||
"in length",
|
||||
},
|
||||
}
|
||||
|
||||
func TestDNSLabel(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tt := range dnsLabelTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// generate lots of labels to increase the chances of catching any
|
||||
@@ -559,7 +584,7 @@ func TestDNSLabel(t *testing.T) {
|
||||
}
|
||||
|
||||
if tt.errIs != nil {
|
||||
require.True(t, errors.Is(err, errDNSLabelLength))
|
||||
require.ErrorIs(t, err, tt.errIs)
|
||||
}
|
||||
|
||||
if tt.errStr != "" {
|
||||
@@ -581,6 +606,8 @@ func BenchmarkDNSLabel(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := regexp.MustCompile(
|
||||
`^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$`,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user