Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A "design by contract" implementation in golang.

License

NotificationsYou must be signed in to change notification settings

openacid/must

Repository files navigation

must is a "design by contract" implementation in golang,for addressing silent bug that is caused by unexpected input etc.

"Design by contract" requires that some conditionsMUST be satisfied for the input of afunction, thus the function does not need to do a lot check on arguments.

It is the responsibility ofmust to enable these checking in a test env and todisable them in production env(for performance concern).

Travis-CIGoDocReport cardGolangCISourcegraphstability-stable

Usage

To enable expectation check in test environment, usego build|test -tags debug.To disable it for a release, justgo build.

package mainimport ("fmt""math/bits""github.com/openacid/must")funcrshift(a,bint)int {// "go build" emits a single No-op instruction.// "go build -tags debug" will call the function and to the checking.must.Be.OK(func() {must.Be.NotZero(b)must.Be.True(bits.TrailingZeros(uint(a))>2,"a must be multiple of 8")})returna>>uint(b)}funcmain() {// panic at line 19 with "go run -tags debug"fmt.Println(rshift(0xf,1))}

With the above code:

Enable check withgo run -tags debug ..It would panic becausea does not satisfy the inputexpectation:

panic:        ...        Error:          Should be true        Messages:       a must be multiple of 8

Disable check withgo run .It just silently ignores the expectation and print the result:

7

Performance impact

  • Without debug,must statement generates only aNOPL instruction.Thus the performance impact is unnoticeable.

  • With debug, there are checking statement instructions generated.

  • BUT, usingmust.Be.OK() creates a closure,which hinders inlining a function. Seegolang-inline-rules :

Function Inlining

Only short and simple functions are inlined. To be inlined a function mustcontain less than ~40 expressions and does not contain complex things likefunction calls, loops, labels, closures, panic's, recover's, select's,switch'es, etc.

Since inlining function is part of golang compile time optimization for smallfunctions,there will introduce a minor portion of performance impact if you have a lotcalls to small functions.

Debug mode

> go build -o bin-release .> go tool objdump -S bin-releaseTEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.go        mustbe.OK(func() {  0x1246030             90                      NOPL  0x1246031             488b4c2410              MOVQ 0x10(SP), CX        return a >> uint(b)  0x1246036             4883f940                CMPQ $0x40, CX  ...  0x1246050             c3                      RET

Release mode

> go build -tags debug -o bin-debug .> go tool objdump -S bin-debugTEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.gofunc rshift(a, b int) int {  ...        mustbe.OK(func() {  0x12481fd             0f57c0                  XORPS X0, X0  0x1248200             0f110424                MOVUPS X0, 0(SP)  ...        f()  0x124822d             488b1c24                MOVQ 0(SP), BX  ...

API

must uses the populartestify as underlyingasserting engine, thus there is a corresponding function defined for everytestify assertion function.

Andmust.Be.OK(f func()) should be the entry of a set of checks:

must.Be.OK(f func())must.Be.Condition(comp assert.Comparison, msgAndArgs ...interface{})must.Be.Contains(s, contains interface{}, msgAndArgs ...interface{})must.Be.DirExists(path string, msgAndArgs ...interface{})must.Be.ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{})must.Be.Empty(object interface{}, msgAndArgs ...interface{})must.Be.Equal(expected, actual interface{}, msgAndArgs ...interface{})must.Be.EqualError(theError error, errString string, msgAndArgs ...interface{})must.Be.EqualValues(expected, actual interface{}, msgAndArgs ...interface{})must.Be.Error(err error, msgAndArgs ...interface{})must.Be.Exactly(expected, actual interface{}, msgAndArgs ...interface{})must.Be.Fail(failureMessage string, msgAndArgs ...interface{})must.Be.FailNow(failureMessage string, msgAndArgs ...interface{})must.Be.False(value bool, msgAndArgs ...interface{})must.Be.FileExists(path string, msgAndArgs ...interface{})must.Be.Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{})must.Be.InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{})must.Be.InDeltaMapValues(expected, actual interface{}, delta float64, msgAndArgs ...interface{})must.Be.InDeltaSlice(expected, actual interface{}, delta float64, msgAndArgs ...interface{})must.Be.InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})must.Be.InEpsilonSlice(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})must.Be.IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{})must.Be.JSONEq(expected string, actual string, msgAndArgs ...interface{})must.Be.Len(object interface{}, length int, msgAndArgs ...interface{})must.Be.Nil(object interface{}, msgAndArgs ...interface{})must.Be.NoError(err error, msgAndArgs ...interface{})must.Be.NotContains(s, contains interface{}, msgAndArgs ...interface{})must.Be.NotEmpty(object interface{}, msgAndArgs ...interface{})must.Be.NotEqual(expected, actual interface{}, msgAndArgs ...interface{})must.Be.NotNil(object interface{}, msgAndArgs ...interface{})must.Be.NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{})must.Be.NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{})must.Be.NotSubset(list, subset interface{}, msgAndArgs ...interface{})must.Be.NotZero(i interface{}, msgAndArgs ...interface{})must.Be.Panics(f assert.PanicTestFunc, msgAndArgs ...interface{})must.Be.PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{})must.Be.Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{})must.Be.Subset(list, subset interface{}, msgAndArgs ...interface{})must.Be.True(value bool, msgAndArgs ...interface{})must.Be.WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{})must.Be.Zero(i interface{}, msgAndArgs ...interface{})

See:assert-functions

Examples

rshift-simple-check

rshift-composite-check

Install

go get -u github.com/openacid/must

Customize tags

must provides with a default tag "debug" to enable expectation check.It is also very easy to define your own tags.To do this, create two files in one of your package, such asmymust_debug.go andmymust_release.go, like following:

mymust_debug.go:

// +build mydebugpackage your_packageimport"github.com/openacid/must/enabled"varmymustBe=enabled.Be

mymust_release.go:

// +build !mydebugpackage your_packageimport"github.com/openacid/must/disabled"varmymustBe=disabled.Be

And replacemust.Be withmymustBe in your source codes.Then your could enable it just by:

go build -tags mydebug

See more:go-build-constraints

About

A "design by contract" implementation in golang.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp