Changes
4 changed files (+172/-69)
-
-
@@ -9,19 +9,19 @@ import (type Ref string type Context struct { URL Ref `jsonld:"_"` URL Ref `jsonld:"@url"` Language activitypub.NaturalLanguageValue `jsonld:"@language,omitempty,collapsible"` } func (c *Context) Ref() Ref { return Ref(c.URL) } func (r *Ref) MarshalText() ([]byte, error) { return []byte(*r), nil } func (c *Context) MarshalJSON() ([]byte, error) { var a map[string]interface{} a = getMap(c) a = reflectToJsonLdMap(c) return json.Marshal(a) }
-
-
-
@@ -2,42 +2,54 @@ package jsonldimport ( "encoding/json" "fmt" "reflect" "strings" ) const ( tagLabel = "jsonld" tagOmitEmpty = "omitempty" tagCollapsible = "collapsible" ) func Marshal(v interface{}, c *Context) ([]byte, error) { p := payloadWithContext{c, &v} return p.MarshalJSON() } type payloadWithContext struct { Context *Context `json:"@context"` Context *Context `jsonld:"@context,omitempty,collapsible"` Obj *interface{} } func IsEmpty(v reflect.Value) bool { var ret bool func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func: ret = v.IsNil() case reflect.Slice, reflect.Map: ret = v.Len() == 0 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() case reflect.Struct: ret = func(reflect.Value) bool { return func(reflect.Value) bool { var ret bool = true for i := 0; i < v.NumField(); i++ { ret = ret && IsEmpty(v.Field(i)) ret = ret && isEmptyValue(v.Field(i)) } return ret }(v) case reflect.String: ret = v.String() == "" case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: ret = v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: ret = v.Uint() == 0 case reflect.Float32, reflect.Float64: ret = v.Float() == 0.0 } return ret return false } func getMap(v interface{}) map[string]interface{} { func reflectToJsonLdMap(v interface{}) map[string]interface{} { a := make(map[string]interface{}) typ := reflect.TypeOf(v) val := reflect.ValueOf(v)
-
@@ -49,14 +61,22 @@ func getMap(v interface{}) map[string]interface{} {for i := 0; i < typ.NumField(); i++ { cField := typ.Field(i) cValue := val.Field(i) cTag := cField.Tag jsonLdTag, ok := loadJsonLdTag(cTag) omitEmpty := ok && jsonLdTag.omitEmpty if jsonLdTag.ignore { continue } if cField.Anonymous { for k, v := range getMap(cValue.Interface()) { for k, v := range reflectToJsonLdMap(cValue.Interface()) { a[k] = v } } else { if !IsEmpty(cValue) { a[cField.Name] = cValue.Interface() } continue } empty := isEmptyValue(cValue) if !empty || empty && !omitEmpty { a[jsonLdName(cField.Name, jsonLdTag)] = cValue.Interface() } }
-
@@ -66,13 +86,31 @@ func getMap(v interface{}) map[string]interface{} {func (p *payloadWithContext) MarshalJSON() ([]byte, error) { a := make(map[string]interface{}) if p.Context != nil { a["@context"] = p.Context.Ref() } typ := reflect.TypeOf(*p) cMirror, _ := typ.FieldByName("Context") jsonLdTag, ok := loadJsonLdTag(cMirror.Tag) omitEmpty := ok && jsonLdTag.omitEmpty collapsible := ok && jsonLdTag.collapsible for k, v := range getMap(*p.Obj) { a[k] = v con := reflectToJsonLdMap(p.Context) if len(con) > 0 || !omitEmpty { for _, v := range con { a[jsonLdName(cMirror.Name, jsonLdTag)] = v if len(con) == 1 && collapsible { break } } } } if *p.Obj != nil { oMap := reflectToJsonLdMap(*p.Obj) if len(oMap) == 0 { return nil, fmt.Errorf("invalid object to marshall") } for k, v := range oMap { a[k] = v } } return json.Marshal(a) }
-
@@ -80,7 +118,45 @@ func (p *payloadWithContext) UnmarshalJSON() {}type Encoder struct{} func Marshal(v interface{}, c *Context) ([]byte, error) { p := payloadWithContext{c, &v} return p.MarshalJSON() type jsonLdTag struct { name string ignore bool omitEmpty bool collapsible bool } func loadJsonLdTag(tag reflect.StructTag) (jsonLdTag, bool) { jlTag, ok := tag.Lookup(tagLabel) if !ok { return jsonLdTag{}, false } val := strings.Split(jlTag, ",") cont := func(arr []string, s string) bool { for _, v := range arr { if v == s { return true } } return false } t := jsonLdTag{ omitEmpty: cont(val, tagOmitEmpty), collapsible: cont(val, tagCollapsible), } t.name, t.ignore = func(v string) (string, bool) { if len(v) > 0 && v != "_" { return v, false } else { return "", true } }(val[0]) return t, true } func jsonLdName(n string, tag jsonLdTag) string { if len(tag.name) > 0 { return tag.name } return n }
-
-
-
@@ -1,11 +1,11 @@package jsonld import ( "bytes" "encoding/json" "reflect" "strings" "testing" "bytes" ) type mockBase struct {
-
@@ -61,13 +61,13 @@ func TestMarshalNullContext(t *testing.T) {var a = struct { PropA string PropB float64 } {"test", 0.0004} }{"test", 0.0004} outL, errL := Marshal(a, nil ) outL, errL := Marshal(a, nil) if errL != nil { t.Errorf("%s", errL) } outJ, errJ := Marshal(a, nil ) outJ, errJ := Marshal(a, nil) if errJ != nil { t.Errorf("%s", errJ) }
-
@@ -78,34 +78,42 @@ func TestMarshalNullContext(t *testing.T) {func TestIsEmpty(t *testing.T) { var a int = 0 if !IsEmpty(reflect.ValueOf(a)) { t.Errorf("Invalid empty valid %s", a) if !isEmptyValue(reflect.ValueOf(a)) { t.Errorf("Invalid empty value %s", a) } if !IsEmpty(reflect.ValueOf(uint(a))) { t.Errorf("Invalid empty valid %s", uint(a)) if !isEmptyValue(reflect.ValueOf(uint(a))) { t.Errorf("Invalid empty value %s", uint(a)) } var b float64 = 0 if !IsEmpty(reflect.ValueOf(b)) { t.Errorf("Invalid empty valid %s", b) if !isEmptyValue(reflect.ValueOf(b)) { t.Errorf("Invalid empty value %s", b) } var c string = "" if !IsEmpty(reflect.ValueOf(c)) { t.Errorf("Invalid empty valid %s", c) if !isEmptyValue(reflect.ValueOf(c)) { t.Errorf("Invalid empty value %s", c) } var d []byte = nil if !IsEmpty(reflect.ValueOf(d)) { t.Errorf("Invalid empty valid %v", d) if !isEmptyValue(reflect.ValueOf(d)) { t.Errorf("Invalid empty value %v", d) } var e *interface{} = nil if !IsEmpty(reflect.ValueOf(e)) { t.Errorf("Invalid empty valid %v", e) if !isEmptyValue(reflect.ValueOf(e)) { t.Errorf("Invalid empty value %v", e) } f := struct { a string b int }{} if !IsEmpty(reflect.ValueOf(f)) { t.Errorf("Invalid empty valid %v", f) if !isEmptyValue(reflect.ValueOf(f)) { t.Errorf("Invalid empty value %v", f) } g := false if !isEmptyValue(reflect.ValueOf(g)) { t.Errorf("Invalid empty value %v", g) } h := true if isEmptyValue(reflect.ValueOf(h)) { t.Errorf("Invalid empty value %v", h) } }
-
-
-
@@ -1,42 +1,61 @@package tests import ( "testing" "activitypub" "jsonld" "testing" "strings" ) func TestAcceptSerialization(t *testing.T) { o := activitypub.AcceptNew("https://localhost/myactivity") o.Name = make(activitypub.NaturalLanguageValue, 1) o.Name["en"] = "test" obj := activitypub.AcceptNew("https://localhost/myactivity") obj.Name = make(activitypub.NaturalLanguageValue, 1) obj.Name["en"] = "test" ctx := jsonld.Context{URL: "https://www.w3.org/ns/activitystreams"} bytes, err := jsonld.Marshal(o, &ctx) data, err := jsonld.Marshal(obj, &ctx) if err != nil { t.Errorf("Error: %v", err) } t.Logf("%s", bytes) if !strings.Contains(string(data), string(ctx.URL)) { t.Errorf("Could not find context url %#v in output %s", ctx.URL, data) } if !strings.Contains(string(data), string(obj.Id)) { t.Errorf("Could not find id %#v in output %s", string(obj.Id), data) } if !strings.Contains(string(data), string(obj.Name["en"])) { t.Errorf("Could not find name %#v in output %s", string(obj.Name["en"]), data) } if !strings.Contains(string(data), string(obj.Type)) { t.Errorf("Could not find activity type %#v in output %s", obj.Type, data) } } func TestCreateActivityHTTPSerialization(t *testing.T) { id := activitypub.ObjectId("test_object") o := activitypub.AcceptNew(id) o.Name["en"] = "Accept New" obj := activitypub.AcceptNew(id) obj.Name["en"] = "Accept New" baseUri := string(activitypub.ActivityBaseURI) c := jsonld.Context{ URL: jsonld.Ref(baseUri + string(o.Type)), ctx := jsonld.Context{ URL: jsonld.Ref(baseUri + string(obj.Type)), } out, err := jsonld.Marshal(o, &c) data, err := jsonld.Marshal(obj, &ctx) if err != nil { t.Error(err) } outNoC, errNoC := jsonld.Marshal(o, nil) if errNoC != nil { t.Error(errNoC) if !strings.Contains(string(data), string(ctx.URL)) { t.Errorf("Could not find context url %#v in output %s", ctx.URL, data) } if !strings.Contains(string(data), string(obj.Id)) { t.Errorf("Could not find id %#v in output %s", string(obj.Id), data) } if !strings.Contains(string(data), string(obj.Name["en"])) { t.Errorf("Could not find name %#v in output %s", string(obj.Name["en"]), data) } if !strings.Contains(string(data), string(obj.Type)) { t.Errorf("Could not find activity type %#v in output %s", obj.Type, data) } t.Logf("%s\n\n%s", out, outNoC) }
-