From e67d39d0639973d670128130f23222c2b76f0040 Mon Sep 17 00:00:00 2001 From: Seiya <20365512+seiyab@users.noreply.github.com> Date: Mon, 6 May 2024 15:43:10 +0900 Subject: [PATCH] add docs (#9) --- .github/workflows/go.yml | 2 +- README.md | 65 ++++++++++++++++++++++++++++++++++++++++ doc.go | 31 +++++++++++++++++++ teq.go | 16 ++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 doc.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 80574c9..6674b4d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -1,4 +1,4 @@ -name: Go +name: CI on: push: diff --git a/README.md b/README.md new file mode 100644 index 0000000..87c2f67 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# teq + +![CI](https://github.com/seiyab/teq/actions/workflows/go.yml/badge.svg) + +teq is a Go library designed to enhance your testing experience by providing a flexible and customizable way to perform deep equality checks. It's especially useful when you need to compare complex objects or types that have specific equality conditions. + +## Features + +- Transforms: Register a "transform" function that can modify objects before comparison. This allows you to control how equality is determined. For example, by transforming time.Time objects to UTC, you can make your equality checks timezone-insensitive. +- Formats: Register a "format" function that defines how objects are displayed when they are not equal. This is useful for types like time.Time and decimal.Decimal that may not be human-readable in their default format. By registering your own format, you can make the output of your tests more understandable. + +## Installation + +```sh +go get github.com/seiyab/teq@latest +``` + +## Usage + +To use teq, you first need to create a new instance: + +```go +tq := teq.New() +``` + +Then, you can add your transforms and formats: + +```go +// time.Time will be transformed into UTC time. So equality check with `tq` will be timezone-insensitive. +tq.AddTransform(func(d time.Time) time.Time { + return d.In(d.UTC) +}) + +// time.Time will be shown in RFC3339 format when it appear in diff. +tq.AddFormat(func(d time.Time) string { + return d.Format(time.RFC3339) +}) +``` + +Finally, you can use teq to perform deep equality checks in your tests: + +```go +tq.Equal(t, expected, actual) +``` + +If you need "common" equality across your project, we recommend to define function that returns your customized teq. + +```go +func NewTeq() teq.Teq { + tq := teq.New() + tq.AddTransform(/* ... */) + tq.AddTransform(/* ... */) + // : + return tq +} + +// then you can use easily it everywhere +tq := NewTeq() +``` + +## Prior works + +- [testify](https://github.com/stretchr/testify) +- [deepequal.go](https://github.com/weaveworks/scope/blob/12175b96a3456f1c2b050f1e1d6432498ed64d95/test/reflect/deepequal.go) in "github.com/weaveworks/scope/test/reflect" package authored by Weaveworks Ltd +- [go-cmp](https://github.com/google/go-cmp) diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..b99a73c --- /dev/null +++ b/doc.go @@ -0,0 +1,31 @@ +/* +Package teq is a Go library designed to enhance your testing experience by providing a flexible and customizable way to perform deep equality checks. It's especially useful when you need to compare complex objects or types that have specific equality conditions. + +# Features + +- Transforms: Register a "transform" function that can modify objects before comparison. This allows you to control how equality is determined. For example, by transforming time.Time objects to UTC, you can make your equality checks timezone-insensitive. +- Formats: Register a "format" function that defines how objects are displayed when they are not equal. This is useful for types like time.Time and decimal.Decimal that may not be human-readable in their default format. By registering your own format, you can make the output of your tests more understandable. + +# Usage + +To use teq, you first need to create a new instance: + + tq := teq.New() + +Then, you can add your transforms and formats: + + // time.Time will be transformed into UTC time. So equality check with `tq` will be timezone-insensitive. + tq.AddTransform(func(d time.Time) time.Time { + return d.In(d.UTC) + }) + + // time.Time will be shown in RFC3339 format when it appear in diff. + tq.AddFormat(func(d time.Time) string { + return d.Format(time.RFC3339) + }) + +Finally, you can use teq to perform deep equality checks in your tests: + + tq.Equal(t, expected, actual) +*/ +package teq diff --git a/teq.go b/teq.go index c9a8b07..15d9cd7 100644 --- a/teq.go +++ b/teq.go @@ -4,13 +4,16 @@ import ( "reflect" ) +// Teq is a object for deep equality comparison. type Teq struct { + // MaxDepth is the maximum depth of the comparison. Default is 1000. MaxDepth int transforms map[reflect.Type]func(reflect.Value) reflect.Value formats map[reflect.Type]func(reflect.Value) string } +// New returns new instance of Teq. func New() Teq { return Teq{ MaxDepth: 1_000, @@ -20,6 +23,7 @@ func New() Teq { } } +// Equal perform deep equality check and report error if not equal. func (teq Teq) Equal(t TestingT, expected, actual any) bool { t.Helper() defer func() { @@ -34,6 +38,7 @@ func (teq Teq) Equal(t TestingT, expected, actual any) bool { return ok } +// NotEqual perform deep equality check and report error if equal. func (teq Teq) NotEqual(t TestingT, expected, actual any) bool { t.Helper() defer func() { @@ -54,6 +59,12 @@ func (teq Teq) NotEqual(t TestingT, expected, actual any) bool { } +// AddTransform adds a transform function to Teq. +// The transform function must have only one argument and one return value. +// The argument type is the type to be transformed. +// If the passed transform function is not valid, it will panic. +// The transformed value will be used for equality check instead of the original value. +// The transformed value and its internal values won't be transformed to prevent infinite recursion. func (teq *Teq) AddTransform(transform any) { ty := reflect.TypeOf(transform) if ty.Kind() != reflect.Func { @@ -72,6 +83,11 @@ func (teq *Teq) AddTransform(transform any) { teq.transforms[ty.In(0)] = reflectTransform } +// AddFormat adds a format function to Teq. +// The format function must have only one argument and one return value. +// The argument type is the type to be formatted. +// If the passed format function is not valid, it will panic. +// The formatted string will be shown instead of the original value in the error report when the values are not equal. func (teq *Teq) AddFormat(format any) { ty := reflect.TypeOf(format) if ty.Kind() != reflect.Func {