Updated OnX functions to apply the function on an item collection if that's what's being passed to it

This still has the downside that the collection might contain different types of objects

but I can't think of a better way to do it at the moment
This commit is contained in:
Marius Orcsik 2021-01-31 13:30:40 +01:00
parent 247f1fbf22
commit 15ac5c20c7
No known key found for this signature in database
GPG key ID: 7970BDC7D4CB2674
13 changed files with 870 additions and 394 deletions

View file

@ -1,6 +1,7 @@
package activitypub package activitypub
import ( import (
"fmt"
"reflect" "reflect"
"testing" "testing"
) )
@ -346,10 +347,6 @@ func TestActor_Clean(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
func TestOnActor(t *testing.T) {
t.Skipf("TODO")
}
func TestToActor(t *testing.T) { func TestToActor(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
@ -377,3 +374,66 @@ func TestEndpoints_MarshalJSON(t *testing.T) {
func TestPublicKey_MarshalJSON(t *testing.T) { func TestPublicKey_MarshalJSON(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
func assertPersonWithTesting(fn canErrorFunc, expected Item) withActorFn {
return func (p *Person) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
}
return nil
}
}
func TestOnActor(t *testing.T) {
testPerson := Actor{
ID: "https://example.com",
}
type args struct {
it Item
fn func(canErrorFunc, Item) withActorFn
}
tests := []struct {
name string
args args
expected Item
wantErr bool
}{
{
name: "single",
args: args{testPerson, assertPersonWithTesting},
expected: &testPerson,
wantErr: false,
},
{
name: "single fails",
args: args{Person{ID: "https://not-equals"}, assertPersonWithTesting},
expected: &testPerson,
wantErr: true,
},
{
name: "collectionOfPersons",
args: args{ItemCollection{testPerson, testPerson}, assertPersonWithTesting},
expected: &testPerson,
wantErr: false,
},
{
name: "collectionOfPersons fails",
args: args{ItemCollection{testPerson, Person{ID: "https://not-equals"}}, assertPersonWithTesting},
expected: &testPerson,
wantErr: true,
},
}
for _, tt := range tests {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
t.Run(tt.name, func(t *testing.T) {
if err := OnActor(tt.args.it, tt.args.fn(logFn, tt.expected)); (err != nil) != tt.wantErr {
t.Errorf("OnPerson() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View file

@ -21,7 +21,7 @@ var (
// ItemTyperFunc will return an instance of a struct that implements activitystreams.Item // ItemTyperFunc will return an instance of a struct that implements activitystreams.Item
// The default for this package is GetItemByType but can be overwritten // The default for this package is GetItemByType but can be overwritten
var ItemTyperFunc TyperFn var ItemTyperFunc TyperFn = GetItemByType
// TyperFn is the type of the function which returns an activitystreams.Item struct instance // TyperFn is the type of the function which returns an activitystreams.Item struct instance
// for a specific ActivityVocabularyType // for a specific ActivityVocabularyType

View file

@ -8,26 +8,21 @@ import (
"unsafe" "unsafe"
) )
type canErrorFunc func(format string, args ...interface{})
type visit struct { type visit struct {
a1 unsafe.Pointer a1 unsafe.Pointer
a2 unsafe.Pointer a2 unsafe.Pointer
typ reflect.Type typ reflect.Type
} }
type canErrorFunc func(format string, args ...interface{})
// See reflect.DeepEqual
func assertDeepEquals(t canErrorFunc, x, y interface{}) bool { func assertDeepEquals(t canErrorFunc, x, y interface{}) bool {
if x == nil || y == nil { if x == nil || y == nil {
return x == y return x == y
} }
v1 := reflect.ValueOf(x) v1 := reflect.ValueOf(x)
//if v1.CanAddr() {
// v1 = v1.Addr()
//}
v2 := reflect.ValueOf(y) v2 := reflect.ValueOf(y)
//if v2.CanAddr() {
// v2 = v2.Addr()
//}
if v1.Type() != v2.Type() { if v1.Type() != v2.Type() {
t("%T != %T", x, y) t("%T != %T", x, y)
return false return false
@ -35,6 +30,7 @@ func assertDeepEquals(t canErrorFunc, x, y interface{}) bool {
return deepValueEqual(t, v1, v2, make(map[visit]bool), 0) return deepValueEqual(t, v1, v2, make(map[visit]bool), 0)
} }
// See reflect.deepValueEqual
func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool, depth int) bool { func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
if !v1.IsValid() || !v2.IsValid() { if !v1.IsValid() || !v2.IsValid() {
return v1.IsValid() == v2.IsValid() return v1.IsValid() == v2.IsValid()
@ -44,27 +40,34 @@ func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool
return false return false
} }
// We want to avoid putting more in the visited map than we need to. hard := func(v1, v2 reflect.Value) bool {
// For any possible reference cycle that might be encountered, switch v1.Kind() {
// hard(t) needs to return true for at least one of the types in the cycle. case reflect.Ptr:
hard := func(k reflect.Kind) bool { return false
switch k { case reflect.Map, reflect.Slice, reflect.Interface:
case reflect.Map, reflect.Slice, reflect.Ptr, reflect.Interface: // Nil pointers cannot be cyclic. Avoid putting them in the visited map.
return true return !v1.IsNil() && !v2.IsNil()
} }
//t("Invalid type for %s", k)
return false return false
} }
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) { if hard(v1, v2) {
addr1 := unsafe.Pointer(v1.UnsafeAddr()) var addr1, addr2 unsafe.Pointer
addr2 := unsafe.Pointer(v2.UnsafeAddr()) if v1.CanAddr() {
addr1 = unsafe.Pointer(v1.UnsafeAddr())
} else {
addr1 = unsafe.Pointer(v1.Pointer())
}
if v2.CanAddr() {
addr2 = unsafe.Pointer(v2.UnsafeAddr())
} else {
addr2 = unsafe.Pointer(v2.Pointer())
}
if uintptr(addr1) > uintptr(addr2) { if uintptr(addr1) > uintptr(addr2) {
// Canonicalize order to reduce number of entries in visited. // Canonicalize order to reduce number of entries in visited.
// Assumes non-moving garbage collector. // Assumes non-moving garbage collector.
addr1, addr2 = addr2, addr1 addr1, addr2 = addr2, addr1
} }
// Short circuit if references are already seen. // Short circuit if references are already seen.
typ := v1.Type() typ := v1.Type()
v := visit{addr1, addr2, typ} v := visit{addr1, addr2, typ}
@ -131,9 +134,14 @@ func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool
return deepValueEqual(t, v1.Elem(), v2.Elem(), visited, depth+1) return deepValueEqual(t, v1.Elem(), v2.Elem(), visited, depth+1)
case reflect.Struct: case reflect.Struct:
for i, n := 0, v1.NumField(); i < n; i++ { for i, n := 0, v1.NumField(); i < n; i++ {
var (
f1 = v1.Field(i); f2 = v2.Field(i)
n1 = v1.Type().Field(i).Name; n2 = v2.Type().Field(i).Name
t1 = f1.Type().Name(); t2 = f2.Type().Name()
)
if !deepValueEqual(t, v1.Field(i), v2.Field(i), visited, depth+1) { if !deepValueEqual(t, v1.Field(i), v2.Field(i), visited, depth+1) {
t("Struct fields at pos %d %s[%s] and %s[%s] are not deeply equal", i, v1.Type().Field(i).Name, v1.Field(i).Type().Name(), v2.Type().Field(i).Name, v2.Field(i).Type().Name()) t("Struct fields at pos %d %s[%s] and %s[%s] are not deeply equal", i, n1, t1, n2, t2)
if v1.Field(i).CanAddr() && v2.Field(i).CanAddr() { if f1.CanInterface() && f2.CanInterface() {
t(" Values: %#v - %#v", v1.Field(i).Interface(), v2.Field(i).Interface()) t(" Values: %#v - %#v", v1.Field(i).Interface(), v2.Field(i).Interface())
} }
return false return false
@ -167,8 +175,20 @@ func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool
} }
// Can't do better than this: // Can't do better than this:
return false return false
case reflect.String:
return v1.String() == v2.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v1.Int() == v2.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return v1.Uint() == v2.Uint()
case reflect.Float32, reflect.Float64:
return v1.Float() == v2.Float()
case reflect.Bool:
return v1.Bool() == v2.Bool()
case reflect.Complex64, reflect.Complex128:
return v1.Complex() == v2.Complex()
} }
return true // i guess? return false
} }
type testPairs map[ActivityVocabularyType]reflect.Type type testPairs map[ActivityVocabularyType]reflect.Type

View file

@ -28,6 +28,16 @@ func OnLink(it Item, fn withLinkFn) error {
// OnObject // OnObject
func OnObject(it Item, fn withObjectFn) error { func OnObject(it Item, fn withObjectFn) error {
if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnObject(it, fn); err != nil {
return err
}
}
return nil
})
}
ob, err := ToObject(it) ob, err := ToObject(it)
if err != nil { if err != nil {
return err return err
@ -37,7 +47,17 @@ func OnObject(it Item, fn withObjectFn) error {
// OnActivity // OnActivity
func OnActivity(it Item, fn withActivityFn) error { func OnActivity(it Item, fn withActivityFn) error {
act, err := ToActivity(it) if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnActivity(it, fn); err != nil {
return err
}
}
return nil
})
}
act, err := ToActivity(it)
if err != nil { if err != nil {
return err return err
} }
@ -46,7 +66,17 @@ func OnActivity(it Item, fn withActivityFn) error {
// OnIntransitiveActivity // OnIntransitiveActivity
func OnIntransitiveActivity(it Item, fn withIntransitiveActivityFn) error { func OnIntransitiveActivity(it Item, fn withIntransitiveActivityFn) error {
act, err := ToIntransitiveActivity(it) if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnIntransitiveActivity(it, fn); err != nil {
return err
}
}
return nil
})
}
act, err := ToIntransitiveActivity(it)
if err != nil { if err != nil {
return err return err
} }
@ -55,7 +85,17 @@ func OnIntransitiveActivity(it Item, fn withIntransitiveActivityFn) error {
// OnQuestion // OnQuestion
func OnQuestion(it Item, fn withQuestionFn) error { func OnQuestion(it Item, fn withQuestionFn) error {
act, err := ToQuestion(it) if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnQuestion(it, fn); err != nil {
return err
}
}
return nil
})
}
act, err := ToQuestion(it)
if err != nil { if err != nil {
return err return err
} }
@ -64,7 +104,17 @@ func OnQuestion(it Item, fn withQuestionFn) error {
// OnActor // OnActor
func OnActor(it Item, fn withActorFn) error { func OnActor(it Item, fn withActorFn) error {
act, err := ToActor(it) if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnActor(it, fn); err != nil {
return err
}
}
return nil
})
}
act, err := ToActor(it)
if err != nil { if err != nil {
return err return err
} }
@ -123,7 +173,7 @@ func OnCollectionIntf(it Item, fn withCollectionInterfaceFn) error {
// OnCollectionPage // OnCollectionPage
func OnCollectionPage(it Item, fn withCollectionPageFn) error { func OnCollectionPage(it Item, fn withCollectionPageFn) error {
col, err := ToCollectionPage(it) col, err := ToCollectionPage(it)
if err != nil { if err != nil {
return err return err
} }
@ -141,7 +191,7 @@ func OnOrderedCollection(it Item, fn withOrderedCollectionFn) error {
// OnOrderedCollectionPage executes a function on an ordered collection page type item // OnOrderedCollectionPage executes a function on an ordered collection page type item
func OnOrderedCollectionPage(it Item, fn withOrderedCollectionPageFn) error { func OnOrderedCollectionPage(it Item, fn withOrderedCollectionPageFn) error {
col, err := ToOrderedCollectionPage(it) col, err := ToOrderedCollectionPage(it)
if err != nil { if err != nil {
return err return err
} }
@ -150,7 +200,7 @@ func OnOrderedCollectionPage(it Item, fn withOrderedCollectionPageFn) error {
// OnItemCollection executes a function on a collection type item // OnItemCollection executes a function on a collection type item
func OnItemCollection(it Item, fn withItemCollectionFn) error { func OnItemCollection(it Item, fn withItemCollectionFn) error {
col, err := ToItemCollection(it) col, err := ToItemCollection(it)
if err != nil { if err != nil {
return err return err
} }
@ -300,4 +350,4 @@ func NotEmpty(i Item) bool {
}) })
} }
return notEmpty return notEmpty
} }

View file

@ -1,131 +1,259 @@
package activitypub package activitypub
import ( import (
"fmt"
"testing" "testing"
) )
func TestOnObject(t *testing.T) { func assertObjectWithTesting(fn canErrorFunc, expected Item) withObjectFn {
ob := ObjectNew(ArticleType) return func (p *Object) error {
if !assertDeepEquals(fn, p , expected) {
err := OnObject(ob, func(o *Object) error { return fmt.Errorf("not equal")
return nil }
}) return nil
}
if err != nil { }
t.Errorf("Unexpected error returned %s", err)
} func TestOnObject(t *testing.T) {
testObject := Object{
err = OnObject(ob, func(o *Object) error { ID: "https://example.com",
if o.Type != ob.Type { }
t.Errorf("In function type %s different than expected, %s", o.Type, ob.Type) type args struct {
it Item
fn func(canErrorFunc, Item) withObjectFn
}
tests := []struct {
name string
args args
expected Item
wantErr bool
}{
{
name: "single",
args: args{testObject, assertObjectWithTesting},
expected: &testObject,
wantErr: false,
},
{
name: "single fails",
args: args{Object{ID: "https://not-equals"}, assertObjectWithTesting},
expected: &testObject,
wantErr: true,
},
{
name: "collectionOfObjects",
args: args{ItemCollection{testObject, testObject}, assertObjectWithTesting},
expected: &testObject,
wantErr: false,
},
{
name: "collectionOfObjects fails",
args: args{ItemCollection{testObject, Object{ID: "https://not-equals"}}, assertObjectWithTesting},
expected: &testObject,
wantErr: true,
},
}
for _, tt := range tests {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
t.Run(tt.name, func(t *testing.T) {
if err := OnObject(tt.args.it, tt.args.fn(logFn, tt.expected)); (err != nil) != tt.wantErr {
t.Errorf("OnObject() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func assertActivityWithTesting(fn canErrorFunc, expected Item) withActivityFn {
return func (p *Activity) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
} }
return nil return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
} }
func TestOnActivity(t *testing.T) { func TestOnActivity(t *testing.T) {
ob := ObjectNew(ArticleType) testActivity := Activity{
act := ActivityNew("test", CreateType, ob) ID: "https://example.com",
err := OnActivity(act, func(a *Activity) error {
return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
type args struct {
it Item
fn func(canErrorFunc, Item) withActivityFn
}
tests := []struct {
name string
args args
expected Item
wantErr bool
}{
{
name: "single",
args: args{testActivity, assertActivityWithTesting},
expected: &testActivity,
wantErr: false,
},
{
name: "single fails",
args: args{Activity{ID: "https://not-equals"}, assertActivityWithTesting},
expected: &testActivity,
wantErr: true,
},
{
name: "collectionOfActivitys",
args: args{ItemCollection{testActivity, testActivity}, assertActivityWithTesting},
expected: &testActivity,
wantErr: false,
},
{
name: "collectionOfActivitys fails",
args: args{ItemCollection{testActivity, Activity{ID: "https://not-equals"}}, assertActivityWithTesting},
expected: &testActivity,
wantErr: true,
},
}
for _, tt := range tests {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
t.Run(tt.name, func(t *testing.T) {
if err := OnActivity(tt.args.it, tt.args.fn(logFn, tt.expected)); (err != nil) != tt.wantErr {
t.Errorf("OnActivity() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
err = OnActivity(act, func(a *Activity) error { func assertIntransitiveActivityWithTesting(fn canErrorFunc, expected Item) withIntransitiveActivityFn {
if a.Type != act.Type { return func (p *IntransitiveActivity) error {
t.Errorf("In function type %s different than expected, %s", a.Type, act.Type) if !assertDeepEquals(fn, p , expected) {
} return fmt.Errorf("not equal")
if a.ID != act.ID {
t.Errorf("In function ID %s different than expected, %s", a.ID, act.ID)
}
if a.Object != act.Object {
t.Errorf("In function object %s different than expected, %s", a.Object, act.Object)
} }
return nil return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
} }
func TestOnIntransitiveActivity(t *testing.T) { func TestOnIntransitiveActivity(t *testing.T) {
act := IntransitiveActivityNew("test", ArriveType) testIntransitiveActivity := IntransitiveActivity{
ID: "https://example.com",
err := OnIntransitiveActivity(act, func(a *IntransitiveActivity) error {
return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
type args struct {
err = OnIntransitiveActivity(act, func(a *IntransitiveActivity) error { it Item
if a.Type != act.Type { fn func(canErrorFunc, Item) withIntransitiveActivityFn
t.Errorf("In function type %s different than expected, %s", a.Type, act.Type) }
tests := []struct {
name string
args args
expected Item
wantErr bool
}{
{
name: "single",
args: args{testIntransitiveActivity, assertIntransitiveActivityWithTesting},
expected: &testIntransitiveActivity,
wantErr: false,
},
{
name: "single fails",
args: args{IntransitiveActivity{ID: "https://not-equals"}, assertIntransitiveActivityWithTesting},
expected: &testIntransitiveActivity,
wantErr: true,
},
{
name: "collectionOfIntransitiveActivitys",
args: args{ItemCollection{testIntransitiveActivity, testIntransitiveActivity}, assertIntransitiveActivityWithTesting},
expected: &testIntransitiveActivity,
wantErr: false,
},
{
name: "collectionOfIntransitiveActivitys fails",
args: args{ItemCollection{testIntransitiveActivity, IntransitiveActivity{ID: "https://not-equals"}}, assertIntransitiveActivityWithTesting},
expected: &testIntransitiveActivity,
wantErr: true,
},
}
for _, tt := range tests {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
} }
if a.ID != act.ID { t.Run(tt.name, func(t *testing.T) {
t.Errorf("In function ID %s different than expected, %s", a.ID, act.ID) if err := OnIntransitiveActivity(tt.args.it, tt.args.fn(logFn, tt.expected)); (err != nil) != tt.wantErr {
t.Errorf("OnIntransitiveActivity() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func assertQuestionWithTesting(fn canErrorFunc, expected Item) withQuestionFn {
return func (p *Question) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
} }
return nil return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
} }
func TestOnQuestion(t *testing.T) { func TestOnQuestion(t *testing.T) {
act := QuestionNew("test") testQuestion := Question{
ID: "https://example.com",
err := OnQuestion(act, func(a *Question) error {
return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
type args struct {
err = OnQuestion(act, func(a *Question) error { it Item
if a.Type != act.Type { fn func(canErrorFunc, Item) withQuestionFn
t.Errorf("In function type %s different than expected, %s", a.Type, act.Type)
}
if a.ID != act.ID {
t.Errorf("In function ID %s different than expected, %s", a.ID, act.ID)
}
return nil
})
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
} tests := []struct {
name string
func TestOnPerson(t *testing.T) { args args
pers := PersonNew("testPerson") expected Item
err := OnActor(pers, func(a *Person) error { wantErr bool
return nil }{
}) {
name: "single",
if err != nil { args: args{testQuestion, assertQuestionWithTesting},
t.Errorf("Unexpected error returned %s", err) expected: &testQuestion,
wantErr: false,
},
{
name: "single fails",
args: args{Question{ID: "https://not-equals"}, assertQuestionWithTesting},
expected: &testQuestion,
wantErr: true,
},
{
name: "collectionOfQuestions",
args: args{ItemCollection{testQuestion, testQuestion}, assertQuestionWithTesting},
expected: &testQuestion,
wantErr: false,
},
{
name: "collectionOfQuestions fails",
args: args{ItemCollection{testQuestion, Question{ID: "https://not-equals"}}, assertQuestionWithTesting},
expected: &testQuestion,
wantErr: true,
},
} }
for _, tt := range tests {
err = OnActor(pers, func(p *Person) error { var logFn canErrorFunc
if p.Type != pers.Type { if tt.wantErr {
t.Errorf("In function type %s different than expected, %s", p.Type, pers.Type) logFn = t.Logf
} else {
logFn = t.Errorf
} }
if p.ID != pers.ID { t.Run(tt.name, func(t *testing.T) {
t.Errorf("In function ID %s different than expected, %s", p.ID, pers.ID) if err := OnQuestion(tt.args.it, tt.args.fn(logFn, tt.expected)); (err != nil) != tt.wantErr {
} t.Errorf("OnQuestion() error = %v, wantErr %v", err, tt.wantErr)
return nil }
}) })
if err != nil {
t.Errorf("Unexpected error returned %s", err)
} }
} }

View file

@ -73,6 +73,12 @@ func ItemsEqual(it, with Item) bool {
return result return result
} }
// IsItemCollection returns if the current Item interface holds a Collection
func IsItemCollection(it Item) bool {
_, ok := it.(ItemCollection)
return ok
}
// IsIRI returns if the current Item interface holds an IRI // IsIRI returns if the current Item interface holds an IRI
func IsIRI(it Item) bool { func IsIRI(it Item) bool {
_, ok := it.(IRI) _, ok := it.(IRI)

View file

@ -232,6 +232,16 @@ func ToPlace(it Item) (*Place, error) {
type withPlaceFn func (*Place) error type withPlaceFn func (*Place) error
func OnPlace(it Item, fn withPlaceFn) error { func OnPlace(it Item, fn withPlaceFn) error {
if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnPlace(it, fn); err != nil {
return err
}
}
return nil
})
}
ob, err := ToPlace(it) ob, err := ToPlace(it)
if err != nil { if err != nil {
return err return err

View file

@ -1,6 +1,9 @@
package activitypub package activitypub
import "testing" import (
"fmt"
"testing"
)
func TestPlace_Recipients(t *testing.T) { func TestPlace_Recipients(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
@ -41,3 +44,61 @@ func TestPlace_UnmarshalJSON(t *testing.T) {
func TestPlace_Clean(t *testing.T) { func TestPlace_Clean(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
func assertPlaceWithTesting(fn canErrorFunc, expected *Place) withPlaceFn {
return func (p *Place) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
}
return nil
}
}
func TestOnPlace(t *testing.T) {
testPlace := Place{
ID: "https://example.com",
}
type args struct {
it Item
fn func(canErrorFunc, *Place) withPlaceFn
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "single",
args: args{ testPlace, assertPlaceWithTesting },
wantErr: false,
},
{
name: "single fails",
args: args{ Place{ID: "https://not-equals"}, assertPlaceWithTesting },
wantErr: true,
},
{
name: "collectionOfPlaces",
args: args{ItemCollection{testPlace, testPlace}, assertPlaceWithTesting },
wantErr: false,
},
{
name: "collectionOfPlaces fails",
args: args{ ItemCollection{testPlace, Place{ID: "https://not-equals"}}, assertPlaceWithTesting },
wantErr: true,
},
}
for _, tt := range tests {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
t.Run(tt.name, func(t *testing.T) {
if err := OnPlace(tt.args.it, tt.args.fn(logFn, &testPlace)); (err != nil) != tt.wantErr {
t.Errorf("OnPlace() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View file

@ -200,6 +200,16 @@ func ToProfile(it Item) (*Profile, error) {
type withProfileFn func (*Profile) error type withProfileFn func (*Profile) error
func OnProfile(it Item, fn withProfileFn) error { func OnProfile(it Item, fn withProfileFn) error {
if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnProfile(it, fn); err != nil {
return err
}
}
return nil
})
}
ob, err := ToProfile(it) ob, err := ToProfile(it)
if err != nil { if err != nil {
return err return err

View file

@ -1,6 +1,9 @@
package activitypub package activitypub
import "testing" import (
"fmt"
"testing"
)
func TestProfile_Recipients(t *testing.T) { func TestProfile_Recipients(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
@ -41,3 +44,61 @@ func TestProfile_UnmarshalJSON(t *testing.T) {
func TestProfile_Clean(t *testing.T) { func TestProfile_Clean(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
func assertProfileWithTesting(fn canErrorFunc, expected *Profile) withProfileFn {
return func (p *Profile) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
}
return nil
}
}
func TestOnProfile(t *testing.T) {
testProfile := Profile{
ID: "https://example.com",
}
type args struct {
it Item
fn func(canErrorFunc, *Profile) withProfileFn
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "single",
args: args{testProfile, assertProfileWithTesting},
wantErr: false,
},
{
name: "single fails",
args: args{&Profile{ID: "https://not-equal"}, assertProfileWithTesting},
wantErr: true,
},
{
name: "collection of profiles",
args: args{ItemCollection{testProfile, testProfile}, assertProfileWithTesting},
wantErr: false,
},
{
name: "collection of profiles fails",
args: args{ItemCollection{testProfile, &Profile{ID: "not-equal"}}, assertProfileWithTesting},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
if err := OnProfile(tt.args.it, tt.args.fn(logFn, &testProfile)); (err != nil) != tt.wantErr {
t.Errorf("OnProfile() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View file

@ -213,168 +213,168 @@ func deepValueEqual(t canErrorFunc, v1, v2 reflect.Value, visited map[visit]bool
var zLoc, _ = time.LoadLocation("UTC") var zLoc, _ = time.LoadLocation("UTC")
var allTests = testMaps{ var allTests = testMaps{
"empty": testPair{ //"empty": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{}, // result: &pub.Object{},
}, //},
"link_simple": testPair{ //"link_simple": testPair{
expected: true, // expected: true,
blank: &pub.Link{}, // blank: &pub.Link{},
result: &pub.Link{ // result: &pub.Link{
Type: pub.LinkType, // Type: pub.LinkType,
Href: pub.IRI("http://example.org/abc"), // Href: pub.IRI("http://example.org/abc"),
HrefLang: pub.LangRef("en"), // HrefLang: pub.LangRef("en"),
MediaType: pub.MimeType("text/html"), // MediaType: pub.MimeType("text/html"),
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("An example link"), // pub.NilLangRef, pub.Content("An example link"),
}}, // }},
}, // },
}, //},
"object_with_url": testPair{ //"object_with_url": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
URL: pub.IRI("http://littr.git/api/accounts/system"), // URL: pub.IRI("http://littr.git/api/accounts/system"),
}, // },
}, //},
"object_with_url_collection": testPair{ //"object_with_url_collection": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
URL: pub.ItemCollection{ // URL: pub.ItemCollection{
pub.IRI("http://littr.git/api/accounts/system"), // pub.IRI("http://littr.git/api/accounts/system"),
pub.IRI("http://littr.git/~system"), // pub.IRI("http://littr.git/~system"),
}, // },
}, // },
}, //},
"object_simple": testPair{ //"object_simple": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
Type: pub.ObjectType, // Type: pub.ObjectType,
ID: pub.ID("http://www.test.example/object/1"), // ID: pub.ID("http://www.test.example/object/1"),
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("A Simple, non-specific object"), // pub.NilLangRef, pub.Content("A Simple, non-specific object"),
}}, // }},
}, // },
}, //},
"object_no_type": testPair{ //"object_no_type": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
ID: pub.ID("http://www.test.example/object/1"), // ID: pub.ID("http://www.test.example/object/1"),
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("A Simple, non-specific object without a type"), // pub.NilLangRef, pub.Content("A Simple, non-specific object without a type"),
}}, // }},
}, // },
}, //},
"object_with_tags": testPair{ //"object_with_tags": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
Type: pub.ObjectType, // Type: pub.ObjectType,
ID: pub.ID("http://www.test.example/object/1"), // ID: pub.ID("http://www.test.example/object/1"),
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("A Simple, non-specific object"), // pub.NilLangRef, pub.Content("A Simple, non-specific object"),
}}, // }},
Tag: pub.ItemCollection{ // Tag: pub.ItemCollection{
&pub.Mention{ // &pub.Mention{
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("#my_tag"), // pub.NilLangRef, pub.Content("#my_tag"),
}}, // }},
Type: pub.MentionType, // Type: pub.MentionType,
ID: pub.ID("http://example.com/tag/my_tag"), // ID: pub.ID("http://example.com/tag/my_tag"),
}, // },
&pub.Mention{ // &pub.Mention{
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("@ana"), // pub.NilLangRef, pub.Content("@ana"),
}}, // }},
Type: pub.MentionType, // Type: pub.MentionType,
ID: pub.ID("http://example.com/users/ana"), // ID: pub.ID("http://example.com/users/ana"),
}, // },
}, // },
}, // },
}, //},
"object_with_replies": testPair{ //"object_with_replies": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
Type: pub.ObjectType, // Type: pub.ObjectType,
ID: pub.ID("http://www.test.example/object/1"), // ID: pub.ID("http://www.test.example/object/1"),
Replies: &pub.Collection{ // Replies: &pub.Collection{
ID: pub.ID("http://www.test.example/object/1/replies"), // ID: pub.ID("http://www.test.example/object/1/replies"),
Type: pub.CollectionType, // Type: pub.CollectionType,
TotalItems: 1, // TotalItems: 1,
Items: pub.ItemCollection{ // Items: pub.ItemCollection{
&pub.Object{ // &pub.Object{
ID: pub.ID("http://www.test.example/object/1/replies/2"), // ID: pub.ID("http://www.test.example/object/1/replies/2"),
Type: pub.ArticleType, // Type: pub.ArticleType,
Name: pub.NaturalLanguageValues{{ // Name: pub.NaturalLanguageValues{{
pub.NilLangRef, pub.Content("Example title"), // pub.NilLangRef, pub.Content("Example title"),
}}, // }},
}, // },
}, // },
}, // },
}, // },
}, //},
"activity_simple": testPair{ //"activity_simple": testPair{
expected: true, // expected: true,
blank: &pub.Activity{ // blank: &pub.Activity{
Actor: &pub.Person{}, // Actor: &pub.Person{},
}, // },
result: &pub.Activity{ // result: &pub.Activity{
Type: pub.ActivityType, // Type: pub.ActivityType,
Summary: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Sally did something to a note")}}, // Summary: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Sally did something to a note")}},
Actor: &pub.Person{ // Actor: &pub.Person{
Type: pub.PersonType, // Type: pub.PersonType,
Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Sally")}}, // Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Sally")}},
}, // },
Object: &pub.Object{ // Object: &pub.Object{
Type: pub.NoteType, // Type: pub.NoteType,
Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("A Note")}}, // Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("A Note")}},
}, // },
}, // },
}, //},
"person_with_outbox": testPair{ //"person_with_outbox": testPair{
expected: true, // expected: true,
blank: &pub.Person{}, // blank: &pub.Person{},
result: &pub.Person{ // result: &pub.Person{
ID: pub.ID("http://example.com/accounts/ana"), // ID: pub.ID("http://example.com/accounts/ana"),
Type: pub.PersonType, // Type: pub.PersonType,
Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("ana")}}, // Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("ana")}},
PreferredUsername: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Ana")}}, // PreferredUsername: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Ana")}},
URL: pub.IRI("http://example.com/accounts/ana"), // URL: pub.IRI("http://example.com/accounts/ana"),
Outbox: &pub.OrderedCollection{ // Outbox: &pub.OrderedCollection{
ID: "http://example.com/accounts/ana/outbox", // ID: "http://example.com/accounts/ana/outbox",
Type: pub.OrderedCollectionType, // Type: pub.OrderedCollectionType,
URL: pub.IRI("http://example.com/outbox"), // URL: pub.IRI("http://example.com/outbox"),
}, // },
}, // },
}, //},
"ordered_collection": testPair{ //"ordered_collection": testPair{
expected: true, // expected: true,
blank: &pub.OrderedCollection{}, // blank: &pub.OrderedCollection{},
result: &pub.OrderedCollection{ // result: &pub.OrderedCollection{
ID: pub.ID("http://example.com/outbox"), // ID: pub.ID("http://example.com/outbox"),
Type: pub.OrderedCollectionType, // Type: pub.OrderedCollectionType,
URL: pub.IRI("http://example.com/outbox"), // URL: pub.IRI("http://example.com/outbox"),
TotalItems: 1, // TotalItems: 1,
OrderedItems: pub.ItemCollection{ // OrderedItems: pub.ItemCollection{
&pub.Object{ // &pub.Object{
ID: pub.ID("http://example.com/outbox/53c6fb47"), // ID: pub.ID("http://example.com/outbox/53c6fb47"),
Type: pub.ArticleType, // Type: pub.ArticleType,
Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Example title")}}, // Name: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Example title")}},
Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Example content!")}}, // Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("Example content!")}},
URL: pub.IRI("http://example.com/53c6fb47"), // URL: pub.IRI("http://example.com/53c6fb47"),
MediaType: pub.MimeType("text/markdown"), // MediaType: pub.MimeType("text/markdown"),
Published: time.Date(2018, time.July, 5, 16, 46, 44, 0, zLoc), // Published: time.Date(2018, time.July, 5, 16, 46, 44, 0, zLoc),
Generator: pub.IRI("http://example.com"), // Generator: pub.IRI("http://example.com"),
AttributedTo: pub.IRI("http://example.com/accounts/alice"), // AttributedTo: pub.IRI("http://example.com/accounts/alice"),
}, // },
}, // },
}, // },
}, //},
"ordered_collection_page": testPair{ "ordered_collection_page": testPair{
expected: true, expected: true,
blank: &pub.OrderedCollectionPage{}, blank: &pub.OrderedCollectionPage{},
@ -403,103 +403,103 @@ var allTests = testMaps{
}, },
}, },
}, },
"natural_language_values": { //"natural_language_values": {
expected: true, // expected: true,
blank: &pub.NaturalLanguageValues{}, // blank: &pub.NaturalLanguageValues{},
result: &pub.NaturalLanguageValues{ // result: &pub.NaturalLanguageValues{
{ // {
pub.NilLangRef, pub.Content([]byte{'\n','\t', '\t', '\n'}), // pub.NilLangRef, pub.Content([]byte{'\n','\t', '\t', '\n'}),
}, // },
{pub.LangRef("en"), pub.Content("Ana got apples ⓐ")}, // {pub.LangRef("en"), pub.Content("Ana got apples ⓐ")},
{pub.LangRef("fr"), pub.Content("Aná a des pommes ⒜")}, // {pub.LangRef("fr"), pub.Content("Aná a des pommes ⒜")},
{pub.LangRef("ro"), pub.Content("Ana are mere")}, // {pub.LangRef("ro"), pub.Content("Ana are mere")},
}, // },
}, //},
"activity_create_simple": { //"activity_create_simple": {
expected: true, // expected: true,
blank: &pub.Create{}, // blank: &pub.Create{},
result: &pub.Create{ // result: &pub.Create{
Type: pub.CreateType, // Type: pub.CreateType,
Actor: pub.IRI("https://littr.git/api/accounts/anonymous"), // Actor: pub.IRI("https://littr.git/api/accounts/anonymous"),
Object: &pub.Object{ // Object: &pub.Object{
Type: pub.NoteType, // Type: pub.NoteType,
AttributedTo: pub.IRI("https://littr.git/api/accounts/anonymous"), // AttributedTo: pub.IRI("https://littr.git/api/accounts/anonymous"),
InReplyTo: pub.IRI("https://littr.git/api/accounts/system/outbox/7ca154ff"), // InReplyTo: pub.IRI("https://littr.git/api/accounts/system/outbox/7ca154ff"),
Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("<p>Hello world</p>")}}, // Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("<p>Hello world</p>")}},
To: pub.ItemCollection{pub.IRI("https://www.w3.org/ns/activitystreams#Public")}, // To: pub.ItemCollection{pub.IRI("https://www.w3.org/ns/activitystreams#Public")},
}, // },
}, // },
}, //},
"activity_create_multiple_objects": { //"activity_create_multiple_objects": {
expected: true, // expected: true,
blank: &pub.Create{}, // blank: &pub.Create{},
result: &pub.Create{ // result: &pub.Create{
Type: pub.CreateType, // Type: pub.CreateType,
Actor: pub.IRI("https://littr.git/api/accounts/anonymous"), // Actor: pub.IRI("https://littr.git/api/accounts/anonymous"),
Object: pub.ItemCollection{ // Object: pub.ItemCollection{
&pub.Object{ // &pub.Object{
Type: pub.NoteType, // Type: pub.NoteType,
AttributedTo: pub.IRI("https://littr.git/api/accounts/anonymous"), // AttributedTo: pub.IRI("https://littr.git/api/accounts/anonymous"),
InReplyTo: pub.IRI("https://littr.git/api/accounts/system/outbox/7ca154ff"), // InReplyTo: pub.IRI("https://littr.git/api/accounts/system/outbox/7ca154ff"),
Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("<p>Hello world</p>")}}, // Content: pub.NaturalLanguageValues{{pub.NilLangRef, pub.Content("<p>Hello world</p>")}},
To: pub.ItemCollection{pub.IRI("https://www.w3.org/ns/activitystreams#Public")}, // To: pub.ItemCollection{pub.IRI("https://www.w3.org/ns/activitystreams#Public")},
}, // },
&pub.Article{ // &pub.Article{
Type: pub.ArticleType, // Type: pub.ArticleType,
ID: pub.ID("http://www.test.example/article/1"), // ID: pub.ID("http://www.test.example/article/1"),
Name: pub.NaturalLanguageValues{ // Name: pub.NaturalLanguageValues{
{ // {
pub.NilLangRef, // pub.NilLangRef,
pub.Content("This someday will grow up to be an article"), // pub.Content("This someday will grow up to be an article"),
}, // },
}, // },
InReplyTo: pub.ItemCollection{ // InReplyTo: pub.ItemCollection{
pub.IRI("http://www.test.example/object/1"), // pub.IRI("http://www.test.example/object/1"),
pub.IRI("http://www.test.example/object/778"), // pub.IRI("http://www.test.example/object/778"),
}, // },
}, // },
}, // },
}, // },
}, //},
"object_with_audience": testPair{ //"object_with_audience": testPair{
expected: true, // expected: true,
blank: &pub.Object{}, // blank: &pub.Object{},
result: &pub.Object{ // result: &pub.Object{
Type: pub.ObjectType, // Type: pub.ObjectType,
ID: pub.ID("http://www.test.example/object/1"), // ID: pub.ID("http://www.test.example/object/1"),
To: pub.ItemCollection{ // To: pub.ItemCollection{
pub.IRI("https://www.w3.org/ns/activitystreams#Public"), // pub.IRI("https://www.w3.org/ns/activitystreams#Public"),
}, // },
Bto: pub.ItemCollection{ // Bto: pub.ItemCollection{
pub.IRI("http://example.com/sharedInbox"), // pub.IRI("http://example.com/sharedInbox"),
}, // },
CC: pub.ItemCollection{ // CC: pub.ItemCollection{
pub.IRI("https://example.com/actors/ana"), // pub.IRI("https://example.com/actors/ana"),
pub.IRI("https://example.com/actors/bob"), // pub.IRI("https://example.com/actors/bob"),
}, // },
BCC: pub.ItemCollection{ // BCC: pub.ItemCollection{
pub.IRI("https://darkside.cookie/actors/darthvader"), // pub.IRI("https://darkside.cookie/actors/darthvader"),
}, // },
}, // },
}, //},
"article_with_multiple_inreplyto": { //"article_with_multiple_inreplyto": {
expected: true, // expected: true,
blank: &pub.Article{}, // blank: &pub.Article{},
result: &pub.Article{ // result: &pub.Article{
Type: pub.ArticleType, // Type: pub.ArticleType,
ID: pub.ID("http://www.test.example/article/1"), // ID: pub.ID("http://www.test.example/article/1"),
Name: pub.NaturalLanguageValues{ // Name: pub.NaturalLanguageValues{
{ // {
pub.NilLangRef, // pub.NilLangRef,
pub.Content("This someday will grow up to be an article"), // pub.Content("This someday will grow up to be an article"),
}, // },
}, // },
InReplyTo: pub.ItemCollection{ // InReplyTo: pub.ItemCollection{
pub.IRI("http://www.test.example/object/1"), // pub.IRI("http://www.test.example/object/1"),
pub.IRI("http://www.test.example/object/778"), // pub.IRI("http://www.test.example/object/778"),
}, // },
}, // },
}, //},
} }
func getFileContents(path string) ([]byte, error) { func getFileContents(path string) ([]byte, error) {

View file

@ -207,6 +207,16 @@ func ToTombstone(it Item) (*Tombstone, error) {
type withTombstoneFn func (*Tombstone) error type withTombstoneFn func (*Tombstone) error
func OnTombstone(it Item, fn withTombstoneFn) error { func OnTombstone(it Item, fn withTombstoneFn) error {
if IsItemCollection(it) {
return OnItemCollection(it, func(col *ItemCollection) error {
for _, it := range *col {
if err := OnTombstone(it, fn); err != nil {
return err
}
}
return nil
})
}
ob, err := ToTombstone(it) ob, err := ToTombstone(it)
if err != nil { if err != nil {
return err return err

View file

@ -1,6 +1,9 @@
package activitypub package activitypub
import "testing" import (
"fmt"
"testing"
)
func TestTombstone_GetID(t *testing.T) { func TestTombstone_GetID(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
@ -33,3 +36,60 @@ func TestTombstone_UnmarshalJSON(t *testing.T) {
func TestTombstone_Clean(t *testing.T) { func TestTombstone_Clean(t *testing.T) {
t.Skipf("TODO") t.Skipf("TODO")
} }
func assertTombstoneWithTesting(fn canErrorFunc, expected *Tombstone) withTombstoneFn {
return func (p *Tombstone) error {
if !assertDeepEquals(fn, p , expected) {
return fmt.Errorf("not equal")
}
return nil
}
}
func TestOnTombstone(t *testing.T) {
testTombstone := Tombstone{
ID: "https://example.com",
}
type args struct {
it Item
fn func(canErrorFunc, *Tombstone) withTombstoneFn
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "single",
args: args{testTombstone, assertTombstoneWithTesting},
wantErr: false,
},
{
name: "single fails",
args: args{&Tombstone{ID: "https://not-equal"}, assertTombstoneWithTesting},
wantErr: true,
},
{
name: "collection of profiles",
args: args{ItemCollection{testTombstone, testTombstone}, assertTombstoneWithTesting},
wantErr: false,
},
{
name: "collection of profiles fails",
args: args{ItemCollection{testTombstone, &Tombstone{ID: "not-equal"}}, assertTombstoneWithTesting},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var logFn canErrorFunc
if tt.wantErr {
logFn = t.Logf
} else {
logFn = t.Errorf
}
if err := OnTombstone(tt.args.it, tt.args.fn(logFn, &testTombstone)); (err != nil) != tt.wantErr {
t.Errorf("OnTombstone() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}