so mamy things...
This commit is contained in:
1 parent
f7a8d416c1
commit
78d50d9a6d
24 files changed
+516
-173
No files matched your search
+23
-13
@@ -4,18 +4,22 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/didiercrunch/doorman/shared"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
const epsilon float64 = 0.0001
|
||||
|
||||
type DoormanValue struct {
|
||||
Name string `json:"name" bson:"name"`
|
||||
Probability float64 `json:"probability" bson:"probability"`
|
||||
Name string `json:"name"`
|
||||
Probability *big.Rat `json:"probability"`
|
||||
}
|
||||
|
||||
type doormanValue struct {
|
||||
Name string
|
||||
Probability string
|
||||
}
|
||||
|
||||
type DoormanId struct {
|
||||
@@ -43,10 +47,15 @@ func NewDoormanDefinition(name string, ownerEmails ...string) *DoormanDefinition
|
||||
|
||||
// a way to quickly create doormen in tests. do not use in real code. will
|
||||
// panic if a doorman is wrongly specify
|
||||
func QuickNewDoormanDefinition(name string, probs ...float64) *DoormanDefinition {
|
||||
func QuickNewDoormanDefinition(name string, probs ...string) *DoormanDefinition {
|
||||
ret := NewDoormanDefinition(name, "natasha@bigtits.com")
|
||||
for i, prob := range probs {
|
||||
ret.Values = append(ret.Values, &DoormanValue{"T" + strconv.Itoa(i), prob})
|
||||
r := new(big.Rat)
|
||||
_, err := fmt.Sscan(prob, r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ret.Values = append(ret.Values, &DoormanValue{"T" + strconv.Itoa(i), r})
|
||||
}
|
||||
if err := ret.Validate("natasha@bigtits.com"); err != nil {
|
||||
panic(err)
|
||||
@@ -79,18 +88,19 @@ func (dmd *DoormanDefinition) AsWriteAccess(email string) bool {
|
||||
}
|
||||
|
||||
func (dmd *DoormanDefinition) ValidateDoormanValueProbabilities() error {
|
||||
var sum float64 = 0
|
||||
sum, zero, one := big.NewRat(0, 1), big.NewRat(0, 1), big.NewRat(1, 1)
|
||||
for _, w := range dmd.Values {
|
||||
|
||||
if p := w.Probability; p < 0-epsilon || p > 1+epsilon {
|
||||
if p := w.Probability; p.Cmp(zero) < 0 || p.Cmp(one) > 0 {
|
||||
return errors.New(fmt.Sprintf("doorman value %v is out of range", p))
|
||||
} else {
|
||||
sum += p
|
||||
sum = new(big.Rat).Add(sum, p)
|
||||
}
|
||||
}
|
||||
if sum < 1-epsilon || sum > 1+epsilon {
|
||||
return errors.New("the sum of the probability must be 1.0")
|
||||
if sum.Cmp(one) != 0 {
|
||||
return errors.New("the sum of the probability must be 1")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -125,7 +135,7 @@ func (dmd *DoormanDefinition) CanBeUpdatedBy(dmd2 *DoormanDefinition) error {
|
||||
func (dmd *DoormanDefinition) AsDoormanUpdatePayload() ([]byte, error) {
|
||||
wu := &shared.DoormanUpdater{Id: dmd.Id.Hex()}
|
||||
wu.Timestamp = time.Now().Unix()
|
||||
wu.Probabilities = make([]float64, len(dmd.Values))
|
||||
wu.Probabilities = make([]*big.Rat, len(dmd.Values))
|
||||
for i, value := range dmd.Values {
|
||||
wu.Probabilities[i] = value.Probability
|
||||
}
|
||||
|
||||
+23
-19
@@ -2,13 +2,17 @@ package doormen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/didiercrunch/doorman/shared"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
)
|
||||
|
||||
var zero = big.NewRat(0, 1)
|
||||
|
||||
const epsilon float64 = 0.0001
|
||||
|
||||
func TestNewDoormanDefinition(t *testing.T) {
|
||||
dmd := NewDoormanDefinition("some_name")
|
||||
if dmd.Id == "" {
|
||||
@@ -33,40 +37,40 @@ func TestValidate(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0}, &DoormanValue{"foo", 0}}}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", zero}, &DoormanValue{"foo", zero}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value names must be unique within a doorman" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0}, &DoormanValue{"", 0}}}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", zero}, &DoormanValue{"", zero}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value cannot be empty" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", -0.25}, &DoormanValue{"bar", 0.5}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value -0.25 is out of range" {
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(-1, 4)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value -1/4 is out of range" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 2.5}, &DoormanValue{"bar", 0.5}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value 2.5 is out of range" {
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(5, 2)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "doorman value 5/2 is out of range" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.75}, &DoormanValue{"bar", 0.5}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1.0" {
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(3, 4)}, &DoormanValue{"bar", big.NewRat(1, 2)}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.2}, &DoormanValue{"bar", 0.2}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1.0" {
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(1, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "the sum of the probability must be 1" {
|
||||
t.Error(err)
|
||||
}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.8}, &DoormanValue{"bar", 0.2}}}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(4, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "A doorman needs at least one owner specify as 'email'." {
|
||||
t.Error(err)
|
||||
}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", 0.8}, &DoormanValue{"bar", 0.2}}, OwnerEmails: []string{"alice"}}
|
||||
dmd = &DoormanDefinition{Name: "foo", Values: []*DoormanValue{&DoormanValue{"foo", big.NewRat(4, 5)}, &DoormanValue{"bar", big.NewRat(1, 5)}}, OwnerEmails: []string{"alice"}}
|
||||
if err := dmd.Validate("bob"); err.Error() != "'bob' is not allow to edit this doorman." {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -91,7 +95,7 @@ func TestAsJson(t *testing.T) {
|
||||
func TestAsDoormanUpdatePayload(t *testing.T) {
|
||||
wd := &DoormanDefinition{}
|
||||
wd.Id = bson.NewObjectId()
|
||||
wd.Values = []*DoormanValue{&DoormanValue{"C", 0.25}, &DoormanValue{"T1", 0.75}}
|
||||
wd.Values = []*DoormanValue{&DoormanValue{"C", big.NewRat(1, 4)}, &DoormanValue{"T1", big.NewRat(3, 4)}}
|
||||
data, err := wd.AsDoormanUpdatePayload()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -106,9 +110,9 @@ func TestAsDoormanUpdatePayload(t *testing.T) {
|
||||
}
|
||||
if len(wu.Probabilities) != 2 {
|
||||
t.Error("bad probability length")
|
||||
} else if math.Abs(wu.Probabilities[0]-0.25) > epsilon {
|
||||
} else if wu.Probabilities[0].Cmp(big.NewRat(1, 4)) != 0 {
|
||||
t.Error("bad first probability")
|
||||
} else if math.Abs(wu.Probabilities[1]-0.75) > epsilon {
|
||||
} else if wu.Probabilities[1].Cmp(big.NewRat(3, 4)) != 0 {
|
||||
t.Error("bad second probability")
|
||||
} else if wu.Timestamp == 0 {
|
||||
t.Error("no time specify")
|
||||
@@ -118,7 +122,7 @@ func TestAsDoormanUpdatePayload(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestQuickNewDoormanDefinition(t *testing.T) {
|
||||
dmd := QuickNewDoormanDefinition("foo", 0.75, 0.25)
|
||||
dmd := QuickNewDoormanDefinition("foo", "0.75", "0.25")
|
||||
if dmd.Name != "foo" {
|
||||
t.Error()
|
||||
}
|
||||
@@ -127,11 +131,11 @@ func TestQuickNewDoormanDefinition(t *testing.T) {
|
||||
t.Error()
|
||||
}
|
||||
|
||||
if dmd.Values[0].Name != "T0" || dmd.Values[0].Probability != 0.75 {
|
||||
if dmd.Values[0].Name != "T0" || dmd.Values[0].Probability.Cmp(big.NewRat(3, 4)) != 0 {
|
||||
t.Error()
|
||||
}
|
||||
|
||||
if dmd.Values[1].Name != "T1" || dmd.Values[1].Probability != 0.25 {
|
||||
if dmd.Values[1].Name != "T1" || dmd.Values[1].Probability.Cmp(big.NewRat(1, 4)) != 0 {
|
||||
t.Error()
|
||||
}
|
||||
if len(dmd.OwnerEmails) != 1 && dmd.OwnerEmails[0] != "natasha@bigtits.com" {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package doormen
|
||||
|
||||
import (
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func (val *DoormanValue) GetBSON() (interface{}, error) {
|
||||
ret := &doormanValue{val.Name, ""}
|
||||
txt, err := val.Probability.MarshalText()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Probability = string(txt)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (val *DoormanValue) SetBSON(raw bson.Raw) error {
|
||||
v := new(doormanValue)
|
||||
if err := raw.Unmarshal(v); err != nil {
|
||||
return err
|
||||
}
|
||||
val.Name = v.Name
|
||||
val.Probability = new(big.Rat)
|
||||
return val.Probability.UnmarshalText([]byte(v.Probability))
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package doormen
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJsonEncoding(t *testing.T) {
|
||||
dmd := QuickNewDoormanDefinition("test json", "1/4", "3/4")
|
||||
data, err := json.Marshal(dmd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
dmd2 := new(DoormanDefinition)
|
||||
if err = json.Unmarshal(data, dmd2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(dmd2, dmd) {
|
||||
t.Error()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBsonEncoding(t *testing.T) {
|
||||
dmd := QuickNewDoormanDefinition("test bson", "1/4", "3/4")
|
||||
data, err := bson.Marshal(dmd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
dmd2 := new(DoormanDefinition)
|
||||
if err = bson.Unmarshal(data, dmd2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !reflect.DeepEqual(dmd2, dmd) {
|
||||
t.Error()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user