Added UnmarshalJSON methods for some types
Add some tests
This commit is contained in:
parent
57dab0cb45
commit
4dc584b0d4
|
@ -837,3 +837,11 @@ func (d Dislike) IsObject() bool {
|
|||
func (d Dislike) IsLink() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
//// UnmarshalJSON
|
||||
//func (a *Activity) UnmarshalJSON(data []byte) error {
|
||||
// ob, err := unmarshal(data, *a)
|
||||
// *a = ob.(Activity)
|
||||
//
|
||||
// return err
|
||||
//}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package activitypub
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
)
|
||||
|
||||
// Actor Types
|
||||
const (
|
||||
|
@ -76,7 +81,7 @@ type Actor struct {
|
|||
// The notion of "context" used is intentionally vague.
|
||||
// The intended function is to serve as a means of grouping objects and activities that share a
|
||||
// common originating context or purpose. An example could be all activities relating to a common project or event.
|
||||
//Context ObjectOrLink `jsonld:"_"`
|
||||
Context ObjectOrLink `jsonld:"_"`
|
||||
// The date and time describing the actual or expected ending time of the object.
|
||||
// When used with an Activity object, for instance, the endTime property specifies the moment
|
||||
// the activity concluded or is expected to conclude.
|
||||
|
@ -365,3 +370,35 @@ func (p Person) GetType() ActivityVocabularyType {
|
|||
func (p Person) GetLink() URI {
|
||||
return p.URL.(URI)
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (a *Actor) UnmarshalJSON(data []byte) error {
|
||||
a.ID = getAPObjectID(data)
|
||||
a.Type = getAPType(data)
|
||||
a.Name = getAPNaturalLanguageField(data, "name")
|
||||
a.PreferredUsername = getAPNaturalLanguageField(data, "preferredUsername")
|
||||
a.Content = getAPNaturalLanguageField(data, "content")
|
||||
u := getURIField(data, "url")
|
||||
if len(u) > 0 {
|
||||
a.URL = u
|
||||
}
|
||||
|
||||
o := OutboxStream{}
|
||||
v, _, _, err := jsonparser.Get(data, "outbox")
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
o.UnmarshalJSON(v)
|
||||
a.Outbox = o
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Person) UnmarshalJSON(data []byte) error {
|
||||
a := Actor(*p)
|
||||
err := a.UnmarshalJSON(data)
|
||||
|
||||
*p = Person(a)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package activitypub
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var validCollectionTypes = [...]ActivityVocabularyType{CollectionType, OrderedCollectionType}
|
||||
|
||||
|
@ -315,6 +317,34 @@ func (o *OrderedCollection) IsObject() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (o *OrderedCollection) UnmarshalJSON(data []byte) error {
|
||||
o.ID = getAPObjectID(data)
|
||||
o.Type = getAPType(data)
|
||||
o.Name = getAPNaturalLanguageField(data, "name")
|
||||
o.Content = getAPNaturalLanguageField(data, "content")
|
||||
u := getURIField(data, "url")
|
||||
if len(u) > 0 {
|
||||
o.URL = u
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (c *Collection) UnmarshalJSON(data []byte) error {
|
||||
c.ID = getAPObjectID(data)
|
||||
c.Type = getAPType(data)
|
||||
c.Name = getAPNaturalLanguageField(data, "name")
|
||||
c.Content = getAPNaturalLanguageField(data, "content")
|
||||
u := getURIField(data, "url")
|
||||
if len(u) > 0 {
|
||||
c.URL = u
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (c *Collection) MarshalJSON() ([]byte, error) {
|
||||
return nil, nil
|
||||
|
|
|
@ -79,3 +79,23 @@ func (i Inbox) IsLink() bool {
|
|||
func (i Inbox) IsObject() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (i *InboxStream) UnmarshalJSON(data []byte) error {
|
||||
c := OrderedCollection(*i)
|
||||
err := c.UnmarshalJSON(data)
|
||||
|
||||
*i = InboxStream(c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (i *Inbox) UnmarshalJSON(data []byte) error {
|
||||
c := OrderedCollection(*i)
|
||||
err := c.UnmarshalJSON(data)
|
||||
|
||||
*i = Inbox(c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -103,3 +103,20 @@ func (m Mention) GetID() ObjectID {
|
|||
func (m Mention) GetType() ActivityVocabularyType {
|
||||
return m.Type
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (l *Link) UnmarshalJSON(data []byte) error {
|
||||
l.ID = getAPObjectID(data)
|
||||
l.Type = getAPType(data)
|
||||
l.MediaType = getAPMimeType(data)
|
||||
l.Name = getAPNaturalLanguageField(data, "name")
|
||||
l.HrefLang = getAPLangRefField(data, "hrefLang")
|
||||
u := getURIField(data, "href")
|
||||
if len(u) > 0 {
|
||||
l.Href = u
|
||||
}
|
||||
|
||||
//fmt.Printf("%s\n %#v", data, l)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
229
activitypub/marshalling.go
Normal file
229
activitypub/marshalling.go
Normal file
|
@ -0,0 +1,229 @@
|
|||
package activitypub
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func getAPObjectByType(typ ActivityVocabularyType) (interface{}, error) {
|
||||
var ret interface{}
|
||||
var err error
|
||||
|
||||
switch typ {
|
||||
case ObjectType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case LinkType:
|
||||
ret = Link{}
|
||||
o := ret.(Link)
|
||||
o.Type = typ
|
||||
case ActivityType:
|
||||
ret = Activity{}
|
||||
o := ret.(Activity)
|
||||
o.Type = typ
|
||||
case IntransitiveActivityType:
|
||||
ret = IntransitiveActivity{}
|
||||
o := ret.(IntransitiveActivity)
|
||||
o.Type = typ
|
||||
case ActorType:
|
||||
ret = Actor{}
|
||||
o := ret.(Actor)
|
||||
o.Type = typ
|
||||
case CollectionType:
|
||||
ret = Collection{}
|
||||
o := ret.(Collection)
|
||||
o.Type = typ
|
||||
case OrderedCollectionType:
|
||||
ret = Link{}
|
||||
o := ret.(Link)
|
||||
o.Type = typ
|
||||
case ArticleType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case AudioType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case DocumentType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case EventType:
|
||||
o := Object{}
|
||||
o.Type = typ
|
||||
case ImageType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case NoteType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
ret = o
|
||||
case PageType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case PlaceType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case ProfileType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case RelationshipType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case TombstoneType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case VideoType:
|
||||
ret = Object{}
|
||||
o := ret.(Object)
|
||||
o.Type = typ
|
||||
case MentionType:
|
||||
ret = Mention{}
|
||||
o := ret.(Mention)
|
||||
o.Type = typ
|
||||
case ApplicationType:
|
||||
ret = Application{}
|
||||
o := ret.(Application)
|
||||
o.Type = typ
|
||||
case GroupType:
|
||||
ret = Group{}
|
||||
o := ret.(Group)
|
||||
o.Type = typ
|
||||
case OrganizationType:
|
||||
ret = Organization{}
|
||||
o := ret.(Organization)
|
||||
o.Type = typ
|
||||
case PersonType:
|
||||
ret = Person{}
|
||||
o := ret.(Person)
|
||||
o.Type = typ
|
||||
case ServiceType:
|
||||
ret = Service{}
|
||||
o := ret.(Service)
|
||||
o.Type = typ
|
||||
case AcceptType:
|
||||
ret = Accept{}
|
||||
o := ret.(Accept)
|
||||
o.Type = typ
|
||||
case AddType:
|
||||
ret = Add{}
|
||||
o := ret.(Add)
|
||||
o.Type = typ
|
||||
case AnnounceType:
|
||||
ret = Announce{}
|
||||
o := ret.(Announce)
|
||||
o.Type = typ
|
||||
case ArriveType:
|
||||
ret = Arrive{}
|
||||
o := ret.(Arrive)
|
||||
o.Type = typ
|
||||
case BlockType:
|
||||
ret = Block{}
|
||||
o := ret.(Block)
|
||||
o.Type = typ
|
||||
case CreateType:
|
||||
ret = Create{}
|
||||
o := ret.(Create)
|
||||
o.Type = typ
|
||||
case DeleteType:
|
||||
ret = Delete{}
|
||||
o := ret.(Delete)
|
||||
o.Type = typ
|
||||
case DislikeType:
|
||||
ret = Dislike{}
|
||||
o := ret.(Dislike)
|
||||
o.Type = typ
|
||||
case FlagType:
|
||||
ret = Flag{}
|
||||
o := ret.(Flag)
|
||||
o.Type = typ
|
||||
case FollowType:
|
||||
ret = Follow{}
|
||||
o := ret.(Follow)
|
||||
o.Type = typ
|
||||
case IgnoreType:
|
||||
ret = Ignore{}
|
||||
o := ret.(Ignore)
|
||||
o.Type = typ
|
||||
case InviteType:
|
||||
ret = Invite{}
|
||||
o := ret.(Invite)
|
||||
o.Type = typ
|
||||
case JoinType:
|
||||
ret = Join{}
|
||||
o := ret.(Join)
|
||||
o.Type = typ
|
||||
case LeaveType:
|
||||
ret = Leave{}
|
||||
o := ret.(Leave)
|
||||
o.Type = typ
|
||||
case LikeType:
|
||||
ret = Like{}
|
||||
o := ret.(Like)
|
||||
o.Type = typ
|
||||
case ListenType:
|
||||
ret = Listen{}
|
||||
o := ret.(Listen)
|
||||
o.Type = typ
|
||||
case MoveType:
|
||||
ret = Move{}
|
||||
o := ret.(Move)
|
||||
o.Type = typ
|
||||
case OfferType:
|
||||
ret = Offer{}
|
||||
o := ret.(Offer)
|
||||
o.Type = typ
|
||||
case QuestionType:
|
||||
ret = Question{}
|
||||
o := ret.(Question)
|
||||
o.Type = typ
|
||||
case RejectType:
|
||||
ret = Reject{}
|
||||
o := ret.(Reject)
|
||||
o.Type = typ
|
||||
case ReadType:
|
||||
ret = Read{}
|
||||
o := ret.(Read)
|
||||
o.Type = typ
|
||||
case RemoveType:
|
||||
ret = Remove{}
|
||||
o := ret.(Remove)
|
||||
o.Type = typ
|
||||
case TentativeRejectType:
|
||||
ret = TentativeReject{}
|
||||
o := ret.(TentativeReject)
|
||||
o.Type = typ
|
||||
case TentativeAcceptType:
|
||||
ret = TentativeAccept{}
|
||||
o := ret.(TentativeAccept)
|
||||
o.Type = typ
|
||||
case TravelType:
|
||||
ret = Travel{}
|
||||
o := ret.(Travel)
|
||||
o.Type = typ
|
||||
case UndoType:
|
||||
ret = Undo{}
|
||||
o := ret.(Undo)
|
||||
o.Type = typ
|
||||
case UpdateType:
|
||||
ret = Update{}
|
||||
o := ret.(Update)
|
||||
o.Type = typ
|
||||
case ViewType:
|
||||
ret = View{}
|
||||
o := ret.(View)
|
||||
o.Type = typ
|
||||
default:
|
||||
ret = nil
|
||||
err = fmt.Errorf("%q unrecognized ActivityPub type", typ)
|
||||
}
|
||||
return ret, err
|
||||
}
|
|
@ -86,7 +86,7 @@ type (
|
|||
ActivityVocabularyType string
|
||||
// ActivityObject is a subtype of Object that describes some form of action that may happen,
|
||||
// is currently happening, or has already happened
|
||||
ActivityObject interface{
|
||||
ActivityObject interface {
|
||||
GetID() ObjectID
|
||||
}
|
||||
// ObjectOrLink describes an object of any kind.
|
||||
|
@ -105,7 +105,10 @@ type (
|
|||
GetLink() URI
|
||||
}
|
||||
// ImageOrLink is an interface that Image and Link structs implement
|
||||
ImageOrLink interface{}
|
||||
ImageOrLink interface {
|
||||
ObjectOrLink
|
||||
LinkOrURI
|
||||
}
|
||||
// MimeType is the type for MIME types
|
||||
MimeType string
|
||||
// LangRef is the type for a language reference, should be ISO 639-1 language specifier.
|
||||
|
@ -135,6 +138,14 @@ func (n NaturalLanguageValue) MarshalJSON() ([]byte, error) {
|
|||
return json.Marshal(map[LangRef]string(n))
|
||||
}
|
||||
|
||||
// MarshalText serializes the NaturalLanguageValue into Text
|
||||
func (n NaturalLanguageValue) MarshalText() ([]byte, error) {
|
||||
for _, v := range n {
|
||||
return []byte(fmt.Sprintf("%q", v)), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Append is syntactic sugar for resizing the NaturalLanguageValue map
|
||||
// and appending an element
|
||||
func (n *NaturalLanguageValue) Append(lang LangRef, value string) error {
|
||||
|
@ -156,8 +167,17 @@ func (l *LangRef) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalText tries to load the NaturalLanguage array from the incoming Text value
|
||||
func (l *LangRef) UnmarshalText(data []byte) error {
|
||||
*l = LangRef(data[1 : len(data)-1])
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON tries to load the NaturalLanguage array from the incoming json value
|
||||
func (n *NaturalLanguageValue) UnmarshalJSON(data []byte) error {
|
||||
if data == nil || len(data) == 0 {
|
||||
return fmt.Errorf("invalid incoming bytes")
|
||||
}
|
||||
if data[0] == '"' {
|
||||
// a quoted string - loading it to c.URL
|
||||
if data[len(data)-1] != '"' {
|
||||
|
@ -180,11 +200,23 @@ func (n *NaturalLanguageValue) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalText tries to load the NaturalLanguage array from the incoming Text value
|
||||
func (n *NaturalLanguageValue) UnmarshalText(data []byte) error {
|
||||
if data[0] == '"' {
|
||||
// a quoted string - loading it to c.URL
|
||||
if data[len(data)-1] != '"' {
|
||||
return fmt.Errorf("invalid string value when unmarshalling %T value", n)
|
||||
}
|
||||
n.Append(LangRef("-"), string(data[1:len(data)-1]))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Describes an object of any kind.
|
||||
// The Activity Pub Object type serves as the base type for most of the other kinds of objects defined in the Activity Vocabulary,
|
||||
// including other Core types such as Activity, IntransitiveActivity, Collection and OrderedCollection.
|
||||
type Object struct {
|
||||
// Provides the globally unique identifier for anActivity Pub Object or Link.
|
||||
// Provides the globally unique identifier for anActivity Pub Object or Link.
|
||||
ID ObjectID `jsonld:"id,omitempty"`
|
||||
// Identifies the Activity Pub Object or Link type. Multiple values may be specified.
|
||||
Type ActivityVocabularyType `jsonld:"type,omitempty"`
|
||||
|
@ -375,9 +407,18 @@ func (c *ContentType) UnmarshalJSON(data []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//func (o *Object) UnmarshalJSON(data []byte) error {
|
||||
// //_o, err := unmarshalJSONFromType(data, ObjectType)
|
||||
//
|
||||
// //*o = _o.(Object)
|
||||
// return nil
|
||||
//}
|
||||
// UnmarshalJSON
|
||||
func (o *Object) UnmarshalJSON(data []byte) error {
|
||||
o.ID = getAPObjectID(data)
|
||||
o.Type = getAPType(data)
|
||||
o.Name = getAPNaturalLanguageField(data, "name")
|
||||
o.Content = getAPNaturalLanguageField(data, "content")
|
||||
u := getURIField(data, "url")
|
||||
if len(u) > 0 {
|
||||
o.URL = u
|
||||
}
|
||||
|
||||
//fmt.Printf("%s\n %#v", data, o)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ func (o OutboxStream) GetType() ActivityVocabularyType {
|
|||
func (o OutboxStream) IsLink() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsObject returns true for a OutboxStream object
|
||||
func (o OutboxStream) IsObject() bool {
|
||||
return true
|
||||
|
@ -76,3 +77,23 @@ func (o Outbox) IsLink() bool {
|
|||
func (o Outbox) IsObject() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (o *OutboxStream) UnmarshalJSON(data []byte) error {
|
||||
c := OrderedCollection(*o)
|
||||
err := c.UnmarshalJSON(data)
|
||||
|
||||
*o = OutboxStream(c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalJSON
|
||||
func (o *Outbox) UnmarshalJSON(data []byte) error {
|
||||
c := OrderedCollection(*o)
|
||||
err := c.UnmarshalJSON(data)
|
||||
|
||||
*o = Outbox(c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
146
activitypub/unmarshalling.go
Normal file
146
activitypub/unmarshalling.go
Normal file
|
@ -0,0 +1,146 @@
|
|||
package activitypub
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
)
|
||||
|
||||
var (
|
||||
apUnmarshalerType = reflect.TypeOf(new(ObjectOrLink)).Elem()
|
||||
unmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
|
||||
)
|
||||
|
||||
type mockObj map[string]json.RawMessage
|
||||
|
||||
func getType(j json.RawMessage) ActivityVocabularyType {
|
||||
mock := make(mockObj, 0)
|
||||
json.Unmarshal([]byte(j), &mock)
|
||||
|
||||
for key, val := range mock {
|
||||
if strings.ToLower(key) == "type" {
|
||||
return ActivityVocabularyType(strings.Trim(string(val), "\""))
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getAPObjectID(data []byte) ObjectID {
|
||||
i, err := jsonparser.GetString(data, "id")
|
||||
if err != nil {
|
||||
return ObjectID("")
|
||||
}
|
||||
return ObjectID(i)
|
||||
}
|
||||
|
||||
func getAPType(data []byte) ActivityVocabularyType {
|
||||
t, err := jsonparser.GetString(data, "type")
|
||||
typ := ActivityVocabularyType(t)
|
||||
if err != nil {
|
||||
return ActivityVocabularyType("")
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
func getAPMimeType(data []byte) MimeType {
|
||||
t, err := jsonparser.GetString(data, "mediaType")
|
||||
if err != nil {
|
||||
return MimeType("")
|
||||
}
|
||||
return MimeType(t)
|
||||
}
|
||||
|
||||
func getAPNaturalLanguageField(data []byte, prop string) NaturalLanguageValue {
|
||||
n := NaturalLanguageValue{}
|
||||
val, typ, _, err := jsonparser.Get(data, prop)
|
||||
if err != nil {
|
||||
return NaturalLanguageValue(nil)
|
||||
}
|
||||
switch typ {
|
||||
case jsonparser.Object:
|
||||
jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
|
||||
vv, err := jsonparser.GetString(val, string(key))
|
||||
n.Append(LangRef(key), vv)
|
||||
return err
|
||||
}, prop)
|
||||
case jsonparser.String:
|
||||
n.Append("-", string(val))
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
func getURIField(data []byte, prop string) URI {
|
||||
val, err := jsonparser.GetString(data, prop)
|
||||
if err != nil {
|
||||
return URI("")
|
||||
}
|
||||
return URI(val)
|
||||
}
|
||||
|
||||
func getAPLangRefField(data []byte, prop string) LangRef {
|
||||
val, err := jsonparser.GetString(data, prop)
|
||||
if err != nil {
|
||||
return LangRef("")
|
||||
}
|
||||
return LangRef(val)
|
||||
}
|
||||
|
||||
/*
|
||||
func unmarshal(data []byte, a interface{}) (interface{}, error) {
|
||||
ta := make(mockObj, 0)
|
||||
err := jsonld.Unmarshal(data, &ta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
typ := reflect.TypeOf(a)
|
||||
val := reflect.ValueOf(a)
|
||||
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
cField := typ.Field(i)
|
||||
cValue := val.Field(i)
|
||||
cTag := cField.Tag
|
||||
tag, _ := jsonld.LoadJSONLdTag(cTag)
|
||||
|
||||
var vv reflect.Value
|
||||
for key, j := range ta {
|
||||
if j == nil {
|
||||
continue
|
||||
}
|
||||
if key == tag.Name {
|
||||
if cField.Type.Implements(textUnmarshalerType) {
|
||||
m, _ := cValue.Interface().(encoding.TextUnmarshaler)
|
||||
m.UnmarshalText(j)
|
||||
vv = reflect.ValueOf(m)
|
||||
}
|
||||
if cField.Type.Implements(unmarshalerType) {
|
||||
m, _ := cValue.Interface().(json.Unmarshaler)
|
||||
m.UnmarshalJSON(j)
|
||||
vv = reflect.ValueOf(m)
|
||||
}
|
||||
if cField.Type.Implements(apUnmarshalerType) {
|
||||
o := getAPObjectByType(getType(j))
|
||||
if o != nil {
|
||||
jsonld.Unmarshal([]byte(j), o)
|
||||
vv = reflect.ValueOf(o)
|
||||
}
|
||||
}
|
||||
}
|
||||
if vv.CanAddr() {
|
||||
cValue.Set(vv)
|
||||
fmt.Printf("\n\nReflected %q %q => %#v\n\n%#v\n", cField.Name, cField.Type, vv, tag.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
*/
|
|
@ -43,3 +43,15 @@ func (i *IRI) UnmarshalJSON(s []byte) error {
|
|||
*i = IRI(strings.Trim(string(s), "\""))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalText
|
||||
func (u URI) UnmarshalText(s []byte) error {
|
||||
u = URI(strings.Trim(string(s), "\""))
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalText
|
||||
func (i IRI) UnmarshalText(s []byte) error {
|
||||
i = IRI(strings.Trim(string(s), "\""))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Link",
|
||||
"href": "http://example.org/abc",
|
||||
"hreflang": "en",
|
||||
"hrefLang": "en",
|
||||
"mediaType": "text/html",
|
||||
"name": "An example link"
|
||||
}
|
||||
}
|
||||
|
|
4
tests/mocks/object_with_url.json
Normal file
4
tests/mocks/object_with_url.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"@context":"https://www.w3.org/ns/activitystreams",
|
||||
"url":"http://littr.git/api/accounts/system"
|
||||
}
|
13
tests/mocks/person_with_outbox.json
Normal file
13
tests/mocks/person_with_outbox.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "http://example.com/accounts/ana",
|
||||
"type": "Person",
|
||||
"name": "ana",
|
||||
"url": "http://example.com/accounts/ana",
|
||||
"outbox": {
|
||||
"id": "http://example.com/accounts/ana/outbox",
|
||||
"type": "OrderedCollection",
|
||||
"url": "http://example.com/outbox"
|
||||
},
|
||||
"preferredUsername": "Ana"
|
||||
}
|
|
@ -46,6 +46,14 @@ var allTests = tests{
|
|||
},
|
||||
},
|
||||
},
|
||||
"object_with_url": testPair{
|
||||
path: "./mocks/object_with_url.json",
|
||||
expected: true,
|
||||
blank: &a.Object{},
|
||||
result: &a.Object{
|
||||
URL: a.URI("http://littr.git/api/accounts/system"),
|
||||
},
|
||||
},
|
||||
"object_simple": testPair{
|
||||
path: "./mocks/object_simple.json",
|
||||
expected: true,
|
||||
|
@ -60,23 +68,59 @@ var allTests = tests{
|
|||
},
|
||||
//"activity_simple": testPair{
|
||||
// path: "./mocks/activity_simple.json",
|
||||
// expected: true,
|
||||
// expected: false,
|
||||
// blank: &a.Activity{},
|
||||
// result: &a.Activity{
|
||||
// Type: a.ActivityType,
|
||||
// Summary: a.NaturalLanguageValue{a.LangRef("-"): "Sally did something to a note"},
|
||||
// Actor: a.Actor(a.Person{
|
||||
// Type: a.PersonType,
|
||||
// Name: a.NaturalLanguageValue{
|
||||
// a.LangRef("-"): "Sally",
|
||||
// },
|
||||
// }),
|
||||
// Object: a.Object{
|
||||
// Type: a.NoteType,
|
||||
// Name: a.NaturalLanguageValue{
|
||||
// a.LangRef("-"): "A Note",
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
//},
|
||||
"person_with_outbox": testPair{
|
||||
path: "./mocks/person_with_outbox.json",
|
||||
expected: true,
|
||||
blank: &a.Person{},
|
||||
result: &a.Person{
|
||||
ID: a.ObjectID("http://example.com/accounts/ana"),
|
||||
Type: a.PersonType,
|
||||
Name: a.NaturalLanguageValue{
|
||||
a.LangRef("-"): "ana",
|
||||
},
|
||||
PreferredUsername: a.NaturalLanguageValue{
|
||||
a.LangRef("-"): "Ana",
|
||||
},
|
||||
URL: a.URI("http://example.com/accounts/ana"),
|
||||
Outbox: a.OutboxStream{
|
||||
ID: a.ObjectID("http://example.com/accounts/ana/outbox"),
|
||||
Type: a.OrderedCollectionType,
|
||||
URL: a.URI("http://example.com/outbox"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func getFileContents(path string) []byte {
|
||||
f, _ := os.Open(path)
|
||||
func getFileContents(path string) ([]byte, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := make([]byte, 512)
|
||||
io.ReadFull(f, data)
|
||||
data = bytes.Trim(data, "\x00")
|
||||
|
||||
return data
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func Test_ActivityPubUnmarshall(t *testing.T) {
|
||||
|
@ -92,13 +136,17 @@ func Test_ActivityPubUnmarshall(t *testing.T) {
|
|||
}
|
||||
|
||||
for k, pair := range allTests {
|
||||
data := getFileContents(pair.path)
|
||||
|
||||
var data []byte
|
||||
data, err = getFileContents(pair.path)
|
||||
if err != nil {
|
||||
f("Error: %s for %s", err, pair.path)
|
||||
continue
|
||||
}
|
||||
object := pair.blank
|
||||
|
||||
err = j.Unmarshal(data, object)
|
||||
if err != nil {
|
||||
f("Error: %s", err)
|
||||
f("Error: %s for %s", err, data)
|
||||
continue
|
||||
}
|
||||
expLbl := ""
|
||||
|
@ -107,8 +155,19 @@ func Test_ActivityPubUnmarshall(t *testing.T) {
|
|||
}
|
||||
if pair.expected != reflect.DeepEqual(object, pair.result) {
|
||||
f("\n%#v\n should %sequal to\n%#v", object, expLbl, pair.result)
|
||||
oj, e1 := j.Marshal(object)
|
||||
if e1 != nil {
|
||||
f(e1.Error())
|
||||
}
|
||||
tj, e2 := j.Marshal(pair.result)
|
||||
if e2 != nil {
|
||||
f(e2.Error())
|
||||
}
|
||||
|
||||
f("\n%s\n should %sequal to\n%s", oj, expLbl, tj)
|
||||
continue
|
||||
}
|
||||
//fmt.Printf("%#v", object)
|
||||
if err == nil {
|
||||
fmt.Printf(" --- %s: %s\n %s\n", "PASS", k, pair.path)
|
||||
}
|
||||
|
|
Reference in a new issue