huge refactoring

This commit is contained in:
Julien Neuhart
2019-07-23 13:57:18 +02:00
parent f6b357691c
commit 7bfbda4490
105 changed files with 4051 additions and 2667 deletions

View File

@@ -0,0 +1,8 @@
/*
Package xassert is a helper for converting
and/or validating strings.
All functions return our standard xerror.Error
in case of error.
*/
package xassert

View File

@@ -0,0 +1,88 @@
package xassert
import (
"fmt"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
)
// RuleFloat64 is an interface for
// validating a float64.
type RuleFloat64 interface {
with(key string, value float64)
validate() error
}
type baseRuleFloat64 struct {
key string
value float64
}
func (r *baseRuleFloat64) with(key string, value float64) {
r.key = key
r.value = value
}
type ruleFloat64NotInferiorTo struct {
*baseRuleFloat64
lowerBound float64
}
func (r ruleFloat64NotInferiorTo) validate() error {
const op string = "xassert.ruleFloat64NotInferiorTo.validate"
if r.value < r.lowerBound {
return xerror.Invalid(
op,
fmt.Sprintf("'%s' should be > '%f', got '%f'", r.key, r.lowerBound, r.value),
nil,
)
}
return nil
}
/*
Float64NotInferiorTo returns a RuleFloat64 for
validating that a float64 is not inferior to
given lower bound.
*/
func Float64NotInferiorTo(lowerBound float64) RuleFloat64 {
return ruleFloat64NotInferiorTo{
&baseRuleFloat64{},
lowerBound,
}
}
type ruleFloat64NotSuperiorTo struct {
*baseRuleFloat64
upperBound float64
}
func (r ruleFloat64NotSuperiorTo) validate() error {
const op string = "xassert.ruleFloat64NotSuperiorTo.validate"
if r.value > r.upperBound {
return xerror.Invalid(
op,
fmt.Sprintf("'%s' should be < '%f', got '%f'", r.key, r.upperBound, r.value),
nil,
)
}
return nil
}
/*
Float64NotSuperiorTo returns a RuleFloat64 for
validating that a float64 is not superior to
given upper bound.
*/
func Float64NotSuperiorTo(upperBound float64) RuleFloat64 {
return ruleFloat64NotSuperiorTo{
&baseRuleFloat64{},
upperBound,
}
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = RuleFloat64(new(ruleFloat64NotInferiorTo))
_ = RuleFloat64(new(ruleFloat64NotSuperiorTo))
)

View File

@@ -0,0 +1,32 @@
package xassert
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test/internalpkg/xerrortest"
)
func TestFloat64NotInferiorTo(t *testing.T) {
rule := Float64NotInferiorTo(0.0)
// should be OK.
rule.with("FOO", 10.0)
err := rule.validate()
assert.Nil(t, err)
// should not be OK.
rule.with("FOO", -10.0)
err = rule.validate()
xerrortest.AssertError(t, err)
}
func TestFloat64NotSuperiorTo(t *testing.T) {
rule := Float64NotSuperiorTo(0.0)
// should be OK.
rule.with("FOO", -10.0)
err := rule.validate()
assert.Nil(t, err)
// should not be OK.
rule.with("FOO", 10.0)
err = rule.validate()
xerrortest.AssertError(t, err)
}

View File

@@ -0,0 +1,88 @@
package xassert
import (
"fmt"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
)
// RuleInt64 is an interface for
// validating an int64.
type RuleInt64 interface {
with(key string, value int64)
validate() error
}
type baseRuleInt64 struct {
key string
value int64
}
func (r *baseRuleInt64) with(key string, value int64) {
r.key = key
r.value = value
}
type ruleInt64NotInferiorTo struct {
*baseRuleInt64
lowerBound int64
}
func (r ruleInt64NotInferiorTo) validate() error {
const op string = "xassert.ruleInt64NotInferiorTo.validate"
if r.value < r.lowerBound {
return xerror.Invalid(
op,
fmt.Sprintf("'%s' should be > '%d', got '%d'", r.key, r.lowerBound, r.value),
nil,
)
}
return nil
}
/*
Int64NotInferiorTo returns a RuleInt64 for
validating that an int64 is not inferior to
given lower bound.
*/
func Int64NotInferiorTo(lowerBound int64) RuleInt64 {
return &ruleInt64NotInferiorTo{
&baseRuleInt64{},
lowerBound,
}
}
type ruleInt64NotSuperiorTo struct {
*baseRuleInt64
upperBound int64
}
func (r ruleInt64NotSuperiorTo) validate() error {
const op string = "xassert.ruleInt64NotSuperiorTo.validate"
if r.value > r.upperBound {
return xerror.Invalid(
op,
fmt.Sprintf("'%s' should be < '%d', got '%d'", r.key, r.upperBound, r.value),
nil,
)
}
return nil
}
/*
Int64NotSuperiorTo returns a RuleInt64 for
validating that an int64 is not superior to
given upper bound.
*/
func Int64NotSuperiorTo(upperBound int64) RuleInt64 {
return ruleInt64NotSuperiorTo{
&baseRuleInt64{},
upperBound,
}
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = RuleInt64(new(ruleInt64NotInferiorTo))
_ = RuleInt64(new(ruleInt64NotSuperiorTo))
)

View File

@@ -0,0 +1,32 @@
package xassert
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test/internalpkg/xerrortest"
)
func TestInt64NotInferiorTo(t *testing.T) {
rule := Int64NotInferiorTo(0)
// should be OK.
rule.with("FOO", 10)
err := rule.validate()
assert.Nil(t, err)
// should not be OK.
rule.with("FOO", -10)
err = rule.validate()
xerrortest.AssertError(t, err)
}
func TestInt64NotSuperiorTo(t *testing.T) {
rule := Int64NotSuperiorTo(0)
// should be OK.
rule.with("FOO", -10)
err := rule.validate()
assert.Nil(t, err)
// should not be OK.
rule.with("FOO", 10)
err = rule.validate()
xerrortest.AssertError(t, err)
}

View File

@@ -0,0 +1,60 @@
package xassert
import (
"fmt"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
)
// RuleString is an interface for
// validating a string.
type RuleString interface {
with(key, value string)
validate() error
}
type baseRuleString struct {
key string
value string
}
func (r *baseRuleString) with(key, value string) {
r.key = key
r.value = value
}
type ruleStringOneOf struct {
*baseRuleString
values []string
}
func (r ruleStringOneOf) validate() error {
const op string = "xassert.ruleStringOneOf.validate"
for _, v := range r.values {
if r.value == v {
return nil
}
}
return xerror.Invalid(
op,
fmt.Sprintf("'%s' should be one of '%v', got '%s'", r.key, r.values, r.value),
nil,
)
}
/*
StringOneOf returns a RuleString for
validating that a string is one of given
values.
*/
func StringOneOf(values []string) RuleString {
return ruleStringOneOf{
&baseRuleString{},
values,
}
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = RuleString(new(ruleStringOneOf))
)

View File

@@ -0,0 +1,20 @@
package xassert
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test/internalpkg/xerrortest"
)
func TestStringOfOne(t *testing.T) {
rule := StringOneOf([]string{"foo", "bar", "baz"})
// should be OK.
rule.with("FOO", "foo")
err := rule.validate()
assert.Nil(t, err)
// should not be OK.
rule.with("FOO", "qux")
err = rule.validate()
xerrortest.AssertError(t, err)
}

View File

@@ -0,0 +1,185 @@
package xassert
import (
"fmt"
"os"
"strconv"
"github.com/thecodingmachine/gotenberg/internal/pkg/xerror"
)
/*
String applies validation on a string.
If string is empty or validation fails,
returns the default value.
The key is used to identify the value.
*/
func String(key, value, defaultValue string, rules ...RuleString) (string, error) {
const op string = "xassert.String"
result := defaultValue
if value != "" {
result = value
}
for _, rule := range rules {
rule.with(key, result)
if err := rule.validate(); err != nil {
return defaultValue, xerror.New(op, err)
}
}
return result, nil
}
/*
StringFromEnv returns the value of given environment
variable or the default value if not found or
validation fails.
*/
func StringFromEnv(envVar, defaultValue string, rules ...RuleString) (string, error) {
const op string = "xassert.StringFromEnv"
value := os.Getenv(envVar)
result, err := String(envVar, value, defaultValue, rules...)
if err != nil {
return result, xerror.New(op, err)
}
return result, nil
}
/*
Int64 tries to convert a string to an int64.
If string is empty, conversion or validation fails,
returns the default value.
The key is used to identify the value.
*/
func Int64(key, value string, defaultValue int64, rules ...RuleInt64) (int64, error) {
const op string = "xassert.Int64"
result := defaultValue
if value != "" {
parsedValue, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return defaultValue, xerror.Invalid(
op,
fmt.Sprintf("'%s' is not an integer, got '%s'", key, value),
err,
)
}
result = parsedValue
}
for _, rule := range rules {
rule.with(key, result)
if err := rule.validate(); err != nil {
return defaultValue, xerror.New(op, err)
}
}
return result, nil
}
/*
Int64FromEnv returns the int64 representation of the
value of given environment variable.
If not found, empty, conversion or validation fails,
returns the default value.
*/
func Int64FromEnv(envVar string, defaultValue int64, rules ...RuleInt64) (int64, error) {
const op string = "xassert.Int64FromEnv"
value := os.Getenv(envVar)
result, err := Int64(envVar, value, defaultValue, rules...)
if err != nil {
return result, xerror.New(op, err)
}
return result, nil
}
/*
Float64 tries to convert a string to a float64.
If string is empty, conversion or validation fails,
returns the default value.
The key is used to identify the value.
*/
func Float64(key, value string, defaultValue float64, rules ...RuleFloat64) (float64, error) {
const op string = "xassert.Float64"
result := defaultValue
if value != "" {
parsedValue, err := strconv.ParseFloat(value, 64)
if err != nil {
return defaultValue, xerror.Invalid(
op,
fmt.Sprintf("'%s' is not a float, got '%s'", key, value),
err,
)
}
result = parsedValue
}
for _, rule := range rules {
rule.with(key, result)
if err := rule.validate(); err != nil {
return defaultValue, xerror.New(op, err)
}
}
return result, nil
}
/*
Float64FromEnv returns the float64 representation of the
value of given environment variable.
If not found, empty, conversion or validation fails,
returns the default value.
*/
func Float64FromEnv(envVar string, defaultValue float64, rules ...RuleFloat64) (float64, error) {
const op string = "xassert.Float64FromEnv"
value := os.Getenv(envVar)
result, err := Float64(envVar, value, defaultValue, rules...)
if err != nil {
return result, xerror.New(op, err)
}
return result, nil
}
/*
Bool tries to convert a string to a boolean.
If string is empty or conversion fails, returns the
default value.
The key is used to identify the value.
*/
func Bool(key, value string, defaultValue bool) (bool, error) {
const op string = "xassert.Bool"
result := defaultValue
if value != "" {
parsedValue, err := strconv.ParseBool(value)
if err != nil {
return defaultValue, xerror.Invalid(
op,
fmt.Sprintf("'%s' is not a boolean, got '%s'", key, value),
err,
)
}
result = parsedValue
}
return result, nil
}
/*
BoolFromEnv returns the boolean representation of the
value of given environment variable.
If not found, empty or conversion fails, returns the
default value.
*/
func BoolFromEnv(envVar string, defaultValue bool) (bool, error) {
const op string = "xassert.BoolFromEnv"
value := os.Getenv(envVar)
result, err := Bool(envVar, value, defaultValue)
if err != nil {
return result, xerror.New(op, err)
}
return result, nil
}

View File

@@ -0,0 +1,289 @@
package xassert
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test/internalpkg/xerrortest"
)
func TestString(t *testing.T) {
const (
defaultValue string = "FOO"
)
var expected string
rule := StringOneOf([]string{"FOO", "BAR"})
// empty value, result should be equal
// to the default value.
v, err := String("foo", "", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to given value
// as it is one of "FOO" and "BAR".
expected = "FOO"
v, err = String("foo", expected, defaultValue, rule)
assert.Equal(t, expected, v)
assert.Nil(t, err)
// should not be OK as given value is not
// one of "FOO" and "BAR".
v, err = String("foo", "BAZ", defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
}
func TestStringFromEnv(t *testing.T) {
const (
envVar string = "FOO"
defaultValue string = "FOO"
)
var expected string
rule := StringOneOf([]string{"FOO", "BAR"})
// no environment variable set,
// value should be equal to default value.
v, err := StringFromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to environment variable
// value as it is one of "FOO" and "BAR".
expected = "BAR"
os.Setenv(envVar, expected)
v, err = StringFromEnv(envVar, defaultValue, rule)
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value is not one of "FOO" and "BAR".
os.Setenv(envVar, "BAZ")
v, err = StringFromEnv(envVar, defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
}
func TestInt64(t *testing.T) {
const (
defaultValue int64 = 10
)
var expected int64
rule := Int64NotInferiorTo(6)
// empty value, result should be equal
// to the default value.
v, err := Int64("foo", "", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to given value
// but as integer.
v, err = Int64("foo", "5", defaultValue)
expected = 5
assert.Equal(t, expected, v)
assert.Nil(t, err)
// should not be OK as given value is not
// a string representation of an integer.
v, err = Int64("foo", "foo", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
// should not be OK as given value does not
// validate the rule x >= 6.
v, err = Int64("foo", "5", defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
}
func TestInt64FromEnv(t *testing.T) {
const (
envVar string = "FOO"
defaultValue int64 = 10
)
var expected int64
rule := Int64NotInferiorTo(6)
// no environment variable set,
// value should be equal to default value.
v, err := Int64FromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to environment variable
// value but as integer.
os.Setenv(envVar, "5")
v, err = Int64FromEnv(envVar, defaultValue)
expected = 5
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value is not a string representation of an integer.
os.Setenv(envVar, "foo")
v, err = Int64FromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value does not validate the rule x >= 6.
os.Setenv(envVar, "5")
v, err = Int64FromEnv(envVar, defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
}
func TestFloat64(t *testing.T) {
const defaultValue float64 = 10.0
var expected float64
rule := Float64NotInferiorTo(6.0)
// empty value, result should be equal
// to the default value.
v, err := Float64("foo", "", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to given value
// but as float.
v, err = Float64("foo", "5.5", defaultValue)
expected = 5.5
assert.Equal(t, expected, v)
assert.Nil(t, err)
// should not be OK as given value is not
// a string representation of a float.
v, err = Float64("foo", "foo", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
// should not be OK as given value does not
// validate the rule x >= 6.
v, err = Float64("foo", "5", defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
}
func TestFloat64FromEnv(t *testing.T) {
const (
envVar string = "FOO"
defaultValue float64 = 10.0
)
var expected float64
rule := Float64NotInferiorTo(6.0)
// no environment variable set,
// value should be equal to default value.
v, err := Float64FromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to environment variable
// value but as float.
os.Setenv(envVar, "5.5")
v, err = Float64FromEnv(envVar, defaultValue)
expected = 5.5
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value is not a string representation of a float.
os.Setenv(envVar, "foo")
v, err = Float64FromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value does not validate the rule x >= 6.
os.Setenv(envVar, "5")
v, err = Float64FromEnv(envVar, defaultValue, rule)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
}
func TestBool(t *testing.T) {
const defaultValue bool = true
var expected bool
// empty value, result should be equal
// to the default value.
v, err := Bool("foo", "", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to given value
// but as boolean.
v, err = Bool("foo", "1", defaultValue)
expected = true
assert.Equal(t, expected, v)
assert.Nil(t, err)
v, err = Bool("foo", "true", defaultValue)
expected = true
assert.Equal(t, expected, v)
assert.Nil(t, err)
v, err = Bool("foo", "0", defaultValue)
expected = false
assert.Equal(t, expected, v)
assert.Nil(t, err)
v, err = Bool("foo", "false", defaultValue)
expected = false
assert.Equal(t, expected, v)
assert.Nil(t, err)
// should not be OK as given value is not
// a string representation of a boolean.
v, err = Bool("foo", "foo", defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
}
func TestBoolFromEnv(t *testing.T) {
const (
envVar string = "FOO"
defaultValue bool = true
)
var expected bool
// no environment variable set,
// value should be equal to default value.
v, err := BoolFromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
assert.Nil(t, err)
// result should be equal to environment variable
// value but as boolean.
os.Setenv(envVar, "1")
v, err = BoolFromEnv(envVar, defaultValue)
expected = true
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
os.Setenv(envVar, "true")
v, err = BoolFromEnv(envVar, defaultValue)
expected = true
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
os.Setenv(envVar, "0")
v, err = BoolFromEnv(envVar, defaultValue)
expected = false
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
os.Setenv(envVar, "false")
v, err = BoolFromEnv(envVar, defaultValue)
expected = false
assert.Equal(t, expected, v)
assert.Nil(t, err)
os.Unsetenv(envVar)
// should not be OK as environment variable
// value is not a string representation of a boolean.
os.Setenv(envVar, "foo")
v, err = BoolFromEnv(envVar, defaultValue)
expected = defaultValue
assert.Equal(t, expected, v)
xerrortest.AssertError(t, err)
os.Unsetenv(envVar)
}