verifier

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2019 License: Apache-2.0 Imports: 6 Imported by: 2

README

Verifier "Defend against the impossible, because the impossible will happen." Build Status Go Report Card Coverage Status GoDoc

Package verifier provides simple defensive programing primitives.

Some software has higher than usual requirements for availability, safety or security. Often in such projects people practice pragmatic paranoia with specific set of rules. For example: each public function on any level of your application should check all arguments passed to it. Obviously checking for nil pointers, but also states and conditions, that it will rely on.

When you use such approaches your code can become a mess. And sometimes it's hard to distinguish between verification code and underlying business logic.

This small library is built on error handling pattern described by Rob Pike in Go blog called Errors are values.

It helps you quickly transform code from this

if transfer == nil {
	return nil, errors.New("transfer can't be nil")
}
if person == nil {
	return nil, errors.New("person can't be nil")
}
if transfer.Destination == "" {
	return nil, errors.New("transfer destination can't be empty")
}
if transfer.Amount <= 0 {
	return nil, errors.New("transfer amount should be greater than zero")
}
if person.Name == "" {
	return nil, errors.New("name can't be empty")
}
if person.Age < 21 {
	return nil, fmt.Errorf("age should be 21 or higher, but yours: %d", person.Age)
}
if !person.HasLicense {
	return nil, errors.New("customer should have license")
}

to this

verify := verifier.New()
verify.That(transfer != nil, "transfer can't be nil")
verify.That(person != nil, "person can't be nil")
if verify.GetError() != nil {
	return nil, verify.GetError()
}
verify.That(transfer.Destination != "", "transfer destination can't be empty")
verify.That(transfer.Amount > 0, "transfer amount should be greater than zero")
verify.That(person.Name != "", "name can't be empty")
verify.That(person.Age >= 21, "age should be 21 or higher, but yours: %d", person.Age)
verify.That(person.HasLicense, "customer should have license")
if verify.GetError() != nil {
	return nil, verify.GetError()
}

It also can help you to track down unchecked verifiers when you forget to do it

verify := verifier.New()
verify.That(user.HashPermission(READ, ACCOUNTS), "user has no permission to read accounts")

In this example we have forgot to check verifier using verify.GetError() and after some time you'll see in your log such error:

[ERROR] found unhandled verification: verification failure: user has no permission to read accounts
  verification was created here:
  github.com/storozhukBM/verifier_test.TestVerifier
    /Users/bogdanstorozhuk/verification-lib/src/github.com/storozhukBM/verifier/verifier_test.go:91
  testing.tRunner
    /usr/local/Cellar/go/1.10.2/libexec/src/testing/testing.go:777
  runtime.goexit
    /usr/local/Cellar/go/1.10.2/libexec/src/runtime/asm_amd64.s:2361

If you don't want/need such tracking use zero verifier verifier.Verify{}. You can also redirect output from this package using verifier.SetUnhandledVerificationsWriter(io.Writer) method.


There is other libraries that can be useful when you employ defensive programming style

License

Copyright 2018 Bohdan Storozhuk

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Documentation

Overview

Example
package main

import (
	"fmt"
	"github.com/storozhukBM/verifier"
)

type Person struct {
	name       string
	age        int32
	hasLicense bool
}

func main() {
	person := &Person{
		name:       "John Smith",
		age:        42,
		hasLicense: false,
	}
	err := sellAlcohol(person)
	if err != nil {
		fmt.Print(err)
	}
}

func sellAlcohol(p *Person) error {
	verify := verifier.New()
	verify.That(p != nil, "person can't be nil")
	verify.PanicOnError() // use if you don't want to tolerate such errors
	verify.That(p.age >= 21, "age should be 21 or higher, but yours: %d", p.age)
	verify.That(p.hasLicense, "customer should have license")
	if verify.GetError() != nil {
		return verify.GetError()
	}

	fmt.Print("yes, you can have some alcohol")
	return nil
}
Output:

customer should have license

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SetUnhandledVerificationsWriter

func SetUnhandledVerificationsWriter(w io.Writer)

SetUnhandledVerificationsWriter gives you ability to override UnhandledVerificationsWriter (default: os.Stdout).

Types

type Verify

type Verify struct {
	// contains filtered or unexported fields
}

Verify represents verification instance. All checks can be performed on it using `That` or `Predicate` functions. After one failed check all others won't count and predicates won't be evaluated. Use Verify.GetError function to check if there where any during verification process.

func New

func New() *Verify

New creates verification instance (recommended). It tracks verification state. If you forget to check internal error, using `GetError` or `PanicOnError` methods, it will write error message to UnhandledVerificationsWriter (default: os.Stdout). This mechanism will help you track down possible unhandled verifications. If you don't wan't to track anything, create zero verifier `Verify{}`.

func Offensive

func Offensive() *Verify

Offensive creates verification instance (not-recommended). It tracks verification state and stops application process when founds unchecked verification. If you forget to check internal error, using `GetError` or `PanicOnError` methods, it will write error message to UnhandledVerificationsWriter (default: os.Stdout) and WILL STOP YOUR PROCESS. Created for people who adopt offensive programming(https://en.wikipedia.org/wiki/Offensive_programming). This mechanism will help you track down possible unhandled verifications. USE IT WISELY.

func (*Verify) GetError

func (v *Verify) GetError() error

GetError extracts error from internal state to check if there where any during verification process.

func (*Verify) PanicOnError

func (v *Verify) PanicOnError()

PanicOnError panics if there is an error in internal state. Created for people who adopt offensive programming(https://en.wikipedia.org/wiki/Offensive_programming).

func (*Verify) Predicate

func (v *Verify) Predicate(predicate func() bool, message string, args ...interface{}) *Verify

That evaluates predicate passed as first argument. If `predicate() == true`, verification will proceed for other checks. If `predicate() == false`, internal state will be filled with error, using message argument as format in error factory func(message, args...) (default: fmt.Errorf). After the first failed verification all others won't count and predicates won't be evaluated.

func (*Verify) String

func (v *Verify) String() string

String represents verification and it's status as string type.

func (*Verify) That

func (v *Verify) That(positiveCondition bool, message string, args ...interface{}) *Verify

That verifies condition passed as first argument. If `positiveCondition == true`, verification will proceed for other checks. If `positiveCondition == false`, internal state will be filled with error, using message argument as format in error factory func(message, args...) (default: fmt.Errorf). After the first failed verification all others won't count and predicates won't be evaluated.

func (*Verify) WithErrFactory added in v1.2.0

func (v *Verify) WithErrFactory(factory func(string, ...interface{}) error) *Verify

WithErrFactory sets error construction function (default: fmt.Errorf). Use it to set custom error type of error, returned by Verify.GetError().

func (*Verify) WithError added in v1.1.0

func (v *Verify) WithError(positiveCondition bool, err error) *Verify

WithError verifies condition passed as first argument. If `positiveCondition == true`, verification will proceed for other checks. If `positiveCondition == false`, internal state will be filled with error specified as second argument. After the first failed verification all others won't count and predicates won't be evaluated.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL