{"id":21275699,"url":"https://github.com/halimath/expect","last_synced_at":"2025-03-15T13:13:49.653Z","repository":{"id":49065122,"uuid":"517144004","full_name":"halimath/expect","owner":"halimath","description":"Fluent, typesafe and extensible expectations for writing golang tests","archived":false,"fork":false,"pushed_at":"2024-03-02T18:54:16.000Z","size":108,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-03-02T19:45:10.883Z","etag":null,"topics":["assertions","expectations","go","golang","testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/halimath.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}},"created_at":"2022-07-23T19:12:54.000Z","updated_at":"2024-04-14T20:40:35.307Z","dependencies_parsed_at":"2023-11-12T10:30:47.836Z","dependency_job_id":"b2ab0cfe-5585-4030-acfb-6609622931f6","html_url":"https://github.com/halimath/expect","commit_stats":null,"previous_names":["halimath/expect","halimath/expect-go"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/halimath%2Fexpect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/halimath%2Fexpect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/halimath%2Fexpect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/halimath%2Fexpect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/halimath","download_url":"https://codeload.github.com/halimath/expect/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243732303,"owners_count":20338839,"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":["assertions","expectations","go","golang","testing"],"created_at":"2024-11-21T09:36:13.971Z","updated_at":"2025-03-15T13:13:49.634Z","avatar_url":"https://github.com/halimath.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# expect\n\n![CI Status][ci-img-url] \n[![Go Report Card][go-report-card-img-url]][go-report-card-url] \n[![Package Doc][package-doc-img-url]][package-doc-url] \n[![Releases][release-img-url]][release-url]\n\nA library for writing test expectations using golang 1.18 generics to provide a fluent, readable and type-safe \nexpectations.\n\n# Installation\n\nThis module uses golang modules and can be installed with\n\n```shell\ngo get github.com/halimath/expect@main\n```\n\n## A note on upgrades\n\nThis module previously used the module path `get github.com/halimath/expect-go`, preferred dot imports and\nused a different API. If you are upgrading please keep in mind to use the new import path in addition to all\nthe api changes.\n\n# Usage in tests\n\n`expect` provides two packages\n\n```go\nimport \"github.com/halimath/expect\"\n```\n\nimports the core framework and\n\n```go\nimport \"github.com/halimath/expect/is\"\n```\n\nimports the bundled expectations.\n\nThe following example demonstates the basic use:\n\n```go\nexpect.That(t, \n\tis.DeepEqualTo(got, MyStruc{\n    \tFoo: \"bar\",\n    \tSpam: \"eggs\",\n\t}),\n)\n```\n\nThroughout the examples as well as the source code, we use the term _got_ to represent the value _gotten_ from\nsome operation under test (the _actual_ value). We use the term _want_ to describe the _wanted_ (or \n_expected_) value to compare to.\n\nExpectations are written using `expect.That` passing in either a `testing.T`, `testing.B` or `testing.F`\nfollowed by a variable number of `expect.Expectation` values (passing in zero results in a no-op). Here is a\nsomewhat more complex expectation chain:\n\n```go\ngot := []int{2, 3, 5, 7, 11, 13, 17, 19}\n\nexpect.That(t,\n\tis.SliceOfLen(got, 8),\n\tis.SliceContainingInOrder(got, 5, 7, 13),\n)\n```\n\n`expect.That` will execute all expectations in order and report all errors - it behaves just like regular\ncalls to `t.Error`. All failed expecations will be reported at the very end of the test.\n\nIf you want to fail a test immediately - i.e. calling `t.FailNow()` or `t.Fatal(...)`, use the `FailNow` \ndecorator to wrap the expectations. You can combine them with regular onces.\n\n```go\ngot, err := doSomething()\n\nexpect.That(t\n\texpect.FailNow(is.NoError(err)),\n\tis.DeepEqualTo(got, MyStruc{\n    \tFoo: \"bar\",\n    \tSpam: \"eggs\",\n\t}),\n)\n```\n\n## Standard expectations\n\nThe following table shows the predefined expectations provided by `expect`.\n\nExpectation | Type constraints | Description\n-- | -- | --\n`is.EqualTo` | `comparable` | Compares given and wanted for equality using the go `==` operator.\n`is.DeepEqualTo` | `any` | Compares given and wanted for deep equality using reflection.\n`is.NoError` | `error` | Expects the given error value to be `nil`.\n`is.Error` | `error` | Expects that the given error to be a non-`nil` error that is of the given target error by using `errors.Is` \n`is.MapOfLen` | `map` | Expects the given value to be a map containing the given number of entries\n`is.MapContaining` | `map` | Expects the given value to be a map containing a given key, value pair\n`is.SliceOfLen` | `slice` | Expects the given value to be a slice containing the given number of values\n`is.SliceContaining` | `slice` | Expects the given value to be a slice containing a given set of values in any order\n`is.SliceContainingInOrder` | `slice` | Expects the given value to be a slice containing a given list of values in given order\n`is.StringOfLen` | `string` | Expects the given value to be a string containing the given number of bytes (not neccessarily runes)\n`is.StringContaining` | `string` | Expects the given value to be a string containing a given substring\n`is.StringHavingPrefix` | `string` | Expects the given value to be a string having a given prefix\n`is.StringHavingSuffix` | `string` | Expects the given value to be a string having a given suffix\n`is.EqualToStringByLines` | `string` | Similar to EqualTo used on two strings but reports differences on a line-by-line basis\n\n### A note on error testing\n\n`expect` provides two expectations targeting `error` specificially: `is.Error` and `is.NoError`. The later one\nis straight forward and expects the given value to be `nil`. `is.Error` works by applying the standard library\nfunction `errors.Is` and expects the given error to contain the target error as part of its error wrapping\nchain. In addition, `is.Error` also supports the target error to be `nil`. In this case, `is.Error(v, nil)`\nbehaves identical to `is.Error(v)`. This allows an easy and convenient way of writing table based tests that\nexpect both error and non-error conditions.\n\n### `EqualToStringByLines`\n\nThe `EqualToStringByLines` expectation effectively works like `EqualTo` on strings. The difference arises when\nthe two strings are _not_ equal. If both strings are longer, multiline strings, catching a small difference\ncan be hard to do. In those situations `EqualToStringByLines` helps by reporting differences on a per-line\nbasis. This makes locating the differences and fixing code/adjusting the tests much easier. In addition,\n`EqualToStringByLines` supports _transformers_ - simple functions that preprocess each line - before the\ntransformation results are compared. This makes it much easisier to place expected string values in code as\nmultiline raw string literals. Those string literal's lines usually follow the current indentation depth\nwhich makes them unequal to a (flat) given value. Using the `Dedent` transformer can easily compensate for\nthis keeping the expectation indented \"correcly\" (which regards to code formatting) but the test won't fail.\n\n### Deep equality\n\nThe `is.DeepEqualTo` expectation is special as compared to the other ones. It uses a recursive algorithm to \ncompare the given values deeply traversing nested structures using reflection. It handles all primitive types,\ninterfaces, maps, slices, arrays and structs. It reports all differences found so test failures are easy to\ntrack down.\n\nThe equality checking algorithm can be customized on a per-expectation-invocation level using any of the\nfollowing options. All options must be given to the `is.DeepEqualTo` call:\n\n```go\nexpect.That(t,\n\tis.DeepEqualTo(map[string]int{}, map[string]int(nil), NilMapsAreEmpty(false)),\n)\n```\n\n#### Floatint point precision\n\nPassing the `FloatPrecision` option allows you to customize the floating point precision when comparing both\n`float32` and `float64`. The default value is 10 decimal digits.\n\n#### Nil slices and maps\n\nBy default `nil` slices are considered equal to empty ones as well as `nil` maps are considered equal to empty\nones. You can customize this by passing `NilSlicesAreEmpty(false)` or `NilMapsAreEmpty(false)`.\n\n#### Struct fields\n\nStruct fields can be excluded from the comparison using any of the following methods.\n\nPassing `ExcludeUnexportedStructFields(true)` excludes unexported struct fields (those with a name starting\nwith a lower case letter) from the comparison. The default is not to exclude them.\n\nUsing `ExludeTypes` you can exclude all fields with a type given in the list. `ExcludeTypes` is a slice of\n`reflect.Type` so you can pass in any number of types.\n\n`ExcludeFields` allows you to specify path expressions (given as strings) that match a path to a field. The\nsyntax resembles the format used to report differences (so you can simply copy them from the initial test\nfailure). In addition, you can use a wildcard `*` to match any field or index value.\n\nThe following code sample demonstrates the usage:\n\n```go\ntype nested struct {\n\tnestedField string\n}\n\ntype root struct {\n\tstringField string\n\tsliceField  []nested\n\tmapField    map[string]string\n}\n\nfirst := root{\n\tstringField: \"a\",\n\tsliceField: []nested{\n\t\t{nestedField: \"b\"},\n\t},\n\tmapField: map[string]string{\n\t\t\"foo\":  \"bar\",\n\t\t\"spam\": \"eggs\",\n\t},\n}\n\nsecond := root{\n\tstringField: \"a\",\n\tsliceField: []nested{\n\t\t{nestedField: \"c\"},\n\t},\n\tmapField: map[string]string{\n\t\t\"foo\":  \"bar\",\n\t\t\"spam\": \"spam and eggs\",\n\t},\n}\n\nis.DeepEqualTo(first, second, ExcludeFields{\n\t\".sliceField[*].nestedField\",\n\t\".mapField[spam]\",\n})\n```\n\n## Defining you own expectation\n\nDefining you own expectation is very simple: Implement a type that implements the `expect.Expecation` \ninterface which contains a single method: `Expect`. The method receives a `expect.TB` value which is a \nstriped-down version of `testing.TB` (`testing.TB` contains an unexported method and thus cannot be mocked\nin external tests).\n\nPerform the matching steps and invoke any method on `expect.TB` to log a message and/or fail the test.\nMatchers are encouraged to use `Error`, `Errorf` or `Fail` and leave `Fatal`, `Fatalf` an `FailNow` to the\n`expect.FailNow` decorator. This ensures your're expecations are as flexible as the standard ones.\nNevertheless, if your expectation are always meant to fail the test now, its totatly safe to invoke `FailNow`\nand get exactly that behavior.\n\nAs most expecations can be implemented by a closure function, `expect` provides the `expect.ExpectFunc`\nconvenience type. Almost all built-in matchers are implemented using `ExpectFunc`.\n\nThe following example shows how to implement an expectation for asserting that a given number is even. The\nexample uses generics to handle all kinds of integral numbers and uses a constraint interface from the\n[golang.org/x/exp/constraints](https://pkg.go.dev/golang.org/x/exp/constraints) module.\n\n```go\nfunc IsEven[T constraints.Integer](got T) expect.Expectation {\n\treturn expect.ExpectFunc(func(t expect.TB) {\n\t\tif got%2 != 0 {\n\t\t\tt.Errorf(\"expected \u003c%v\u003e to be even\", got)\n\t\t}\n\t})\n}\n\nfunc TestSomething(t *testing.T) {\n\tvar i int = 22\n\texpect.That(t, IsEven(i))\n}\n```\n\n# License\n\nCopyright 2022, 2023 Alexander Metzner.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n[ci-img-url]: https://github.com/halimath/expect/workflows/CI/badge.svg\n[go-report-card-img-url]: https://goreportcard.com/badge/github.com/halimath/expect\n[go-report-card-url]: https://goreportcard.com/report/github.com/halimath/expect\n[package-doc-img-url]: https://img.shields.io/badge/GoDoc-Reference-blue.svg\n[package-doc-url]: https://pkg.go.dev/github.com/halimath/expect\n[release-img-url]: https://img.shields.io/github/v/release/halimath/expect.svg\n[release-url]: https://github.com/halimath/expect/releases","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalimath%2Fexpect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhalimath%2Fexpect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalimath%2Fexpect/lists"}