{"id":20321389,"url":"https://github.com/openacid/must","last_synced_at":"2025-07-18T03:08:43.561Z","repository":{"id":38339574,"uuid":"198032599","full_name":"openacid/must","owner":"openacid","description":"A \"design by contract\" implementation in golang.","archived":false,"fork":false,"pushed_at":"2023-05-19T18:57:28.000Z","size":296,"stargazers_count":7,"open_issues_count":15,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-25T15:03:35.689Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openacid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-21T08:34:32.000Z","updated_at":"2024-05-09T23:27:25.000Z","dependencies_parsed_at":"2024-06-19T05:32:25.449Z","dependency_job_id":"9508398e-d3cc-468c-b60a-9b4936971106","html_url":"https://github.com/openacid/must","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Fmust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Fmust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Fmust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Fmust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openacid","download_url":"https://codeload.github.com/openacid/must/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248465343,"owners_count":21108244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T19:14:50.363Z","updated_at":"2025-04-11T19:10:02.613Z","avatar_url":"https://github.com/openacid.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# must\n\n`must` is a \"design by contract\" implementation in golang,\nfor addressing silent bug that is caused by unexpected input etc.\n\n\"Design by contract\" requires that some conditions **MUST** be satisfied for the input of a\nfunction, thus the function does not need to do a lot check on arguments.\n\nIt is the responsibility of `must` to enable these checking in a test env and to\ndisable them in production env(for performance concern).\n\n[![Travis-CI](https://api.travis-ci.org/openacid/must.svg?branch=master)](https://travis-ci.org/openacid/must)\n[![GoDoc](https://godoc.org/github.com/openacid/must?status.svg)](http://godoc.org/github.com/openacid/must)\n[![Report card](https://goreportcard.com/badge/github.com/openacid/must)](https://goreportcard.com/report/github.com/openacid/must)\n[![GolangCI](https://golangci.com/badges/github.com/openacid/must.svg)](https://golangci.com/r/github.com/openacid/must)\n[![Sourcegraph](https://sourcegraph.com/github.com/openacid/must/-/badge.svg)](https://sourcegraph.com/github.com/openacid/must?badge)\n![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n \n\n- [Usage](#usage)\n  - [Performance impact](#performance-impact)\n    - [Debug mode](#debug-mode)\n    - [Release mode](#release-mode)\n- [API](#api)\n- [Examples](#examples)\n- [Install](#install)\n- [Customize tags](#customize-tags)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Usage\n\nTo enable expectation check in test environment, use `go build|test -tags debug`.\nTo disable it for a release, just `go build`.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/bits\"\n\n\t\"github.com/openacid/must\"\n)\n\nfunc rshift(a, b int) int {\n\n\t// \"go build\" emits a single No-op instruction.\n\t// \"go build -tags debug\" will call the function and to the checking.\n\tmust.Be.OK(func() {\n\t\tmust.Be.NotZero(b)\n\t\tmust.Be.True(bits.TrailingZeros(uint(a)) \u003e 2,\n\t\t\t\"a must be multiple of 8\")\n\t})\n\n\treturn a \u003e\u003e uint(b)\n}\n\nfunc main() {\n\t// panic at line 19 with \"go run -tags debug\"\n\tfmt.Println(rshift(0xf, 1))\n}\n```\n\nWith the above code:\n\n**Enable check** with `go run -tags debug .`.\nIt would panic because `a` does not satisfy the input\nexpectation:\n\n```\npanic:\n        ...\n        Error:          Should be true\n        Messages:       a must be multiple of 8\n```\n\n**Disable check** with `go run .`\nIt just silently ignores the expectation and print the result:\n\n```\n7\n```\n\n## Performance impact\n\n- **Without debug**, `must` statement generates only a `NOPL` instruction.\n  Thus the performance impact is unnoticeable.\n\n- **With debug**, there are checking statement instructions generated.\n\n- **BUT, using `must.Be.OK()` creates a closure,\n  which hinders inlining a function**. See [golang-inline-rules](https://github.com/golang/go/wiki/CompilerOptimizations#function-inlining) :\n\n\u003e Function Inlining\n\u003e\n\u003e Only short and simple functions are inlined. To be inlined a function must\n\u003e contain less than ~40 expressions and does not contain complex things like\n\u003e function calls, loops, labels, closures, panic's, recover's, select's,\n\u003e switch'es, etc.\n\nSince inlining function is part of golang compile time optimization for small\nfunctions,\nthere will introduce a minor portion of performance impact if you  have a lot\ncalls to small functions.\n\n### Debug mode\n\n```\n\u003e go build -o bin-release .\n\u003e go tool objdump -S bin-release\n\nTEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.go\n        mustbe.OK(func() {\n  0x1246030             90                      NOPL\n  0x1246031             488b4c2410              MOVQ 0x10(SP), CX\n        return a \u003e\u003e uint(b)\n  0x1246036             4883f940                CMPQ $0x40, CX\n  ...\n  0x1246050             c3                      RET\n```\n\n### Release mode\n\n```\n\u003e go build -tags debug -o bin-debug .\n\u003e go tool objdump -S bin-debug\n\nTEXT main.rshift(SB) github.com/openacid/must/examples/rshift/composite/main.go\nfunc rshift(a, b int) int {\n  ...\n        mustbe.OK(func() {\n  0x12481fd             0f57c0                  XORPS X0, X0\n  0x1248200             0f110424                MOVUPS X0, 0(SP)\n  ...\n        f()\n  0x124822d             488b1c24                MOVQ 0(SP), BX\n  ...\n```\n\n\n# API\n\n`must` uses the popular [testify](https://github.com/stretchr/testify) as underlying\nasserting engine, thus there is a corresponding function defined for every\n`testify` assertion function.\n\nAnd `must.Be.OK(f func())` should be the entry of a set of checks:\n\n```\nmust.Be.OK(f func())\n\nmust.Be.Condition(comp assert.Comparison, msgAndArgs ...interface{})\nmust.Be.Contains(s, contains interface{}, msgAndArgs ...interface{})\nmust.Be.DirExists(path string, msgAndArgs ...interface{})\nmust.Be.ElementsMatch(listA, listB interface{}, msgAndArgs ...interface{})\nmust.Be.Empty(object interface{}, msgAndArgs ...interface{})\nmust.Be.Equal(expected, actual interface{}, msgAndArgs ...interface{})\nmust.Be.EqualError(theError error, errString string, msgAndArgs ...interface{})\nmust.Be.EqualValues(expected, actual interface{}, msgAndArgs ...interface{})\nmust.Be.Error(err error, msgAndArgs ...interface{})\nmust.Be.Exactly(expected, actual interface{}, msgAndArgs ...interface{})\nmust.Be.Fail(failureMessage string, msgAndArgs ...interface{})\nmust.Be.FailNow(failureMessage string, msgAndArgs ...interface{})\nmust.Be.False(value bool, msgAndArgs ...interface{})\nmust.Be.FileExists(path string, msgAndArgs ...interface{})\nmust.Be.Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{})\nmust.Be.InDelta(expected, actual interface{}, delta float64, msgAndArgs ...interface{})\nmust.Be.InDeltaMapValues(expected, actual interface{}, delta float64, msgAndArgs ...interface{})\nmust.Be.InDeltaSlice(expected, actual interface{}, delta float64, msgAndArgs ...interface{})\nmust.Be.InEpsilon(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})\nmust.Be.InEpsilonSlice(expected, actual interface{}, epsilon float64, msgAndArgs ...interface{})\nmust.Be.IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{})\nmust.Be.JSONEq(expected string, actual string, msgAndArgs ...interface{})\nmust.Be.Len(object interface{}, length int, msgAndArgs ...interface{})\nmust.Be.Nil(object interface{}, msgAndArgs ...interface{})\nmust.Be.NoError(err error, msgAndArgs ...interface{})\nmust.Be.NotContains(s, contains interface{}, msgAndArgs ...interface{})\nmust.Be.NotEmpty(object interface{}, msgAndArgs ...interface{})\nmust.Be.NotEqual(expected, actual interface{}, msgAndArgs ...interface{})\nmust.Be.NotNil(object interface{}, msgAndArgs ...interface{})\nmust.Be.NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{})\nmust.Be.NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{})\nmust.Be.NotSubset(list, subset interface{}, msgAndArgs ...interface{})\nmust.Be.NotZero(i interface{}, msgAndArgs ...interface{})\nmust.Be.Panics(f assert.PanicTestFunc, msgAndArgs ...interface{})\nmust.Be.PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{})\nmust.Be.Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{})\nmust.Be.Subset(list, subset interface{}, msgAndArgs ...interface{})\nmust.Be.True(value bool, msgAndArgs ...interface{})\nmust.Be.WithinDuration(expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{})\nmust.Be.Zero(i interface{}, msgAndArgs ...interface{})\n```\n\nSee: [assert-functions](https://godoc.org/github.com/stretchr/testify/assert)\n\n\n# Examples\n\n[rshift-simple-check](examples/rshift/simple)\n\n[rshift-composite-check](examples/rshift/composite)\n\n\n# Install\n\n```\ngo get -u github.com/openacid/must\n```\n\n\n# Customize tags\n\n`must` provides with a default tag \"debug\" to enable expectation check.\nIt is also very easy to define your own tags.\nTo do this, create two files in one of your package, such as `mymust_debug.go` and `mymust_release.go`, like following:\n\n`mymust_debug.go`:\n\n```go\n// +build mydebug\n\npackage your_package\nimport \"github.com/openacid/must/enabled\"\nvar mymustBe = enabled.Be\n```\n\n`mymust_release.go`:\n\n```go\n// +build !mydebug\n\npackage your_package\nimport \"github.com/openacid/must/disabled\"\nvar mymustBe = disabled.Be\n```\n\nAnd replace `must.Be` with `mymustBe` in your source codes.\nThen your could enable it just by:\n\n```\ngo build -tags mydebug\n```\n\nSee more: [go-build-constraints](https://golang.org/pkg/go/build/#hdr-Build_Constraints)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenacid%2Fmust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenacid%2Fmust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenacid%2Fmust/lists"}