Skip to content

Commit

Permalink
add docs (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
seiyab authored May 6, 2024
1 parent 9a86a68 commit e67d39d
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Go
name: CI

on:
push:
Expand Down
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
31 changes: 31 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions teq.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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() {
Expand All @@ -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() {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit e67d39d

Please # to comment.