]> Cypherpunks repositories - gostls13.git/commitdiff
json: allow using '$' and '-' as the struct field's tag
authorMikio Hara <mikioh.mikioh@gmail.com>
Thu, 14 Jul 2011 00:41:33 +0000 (17:41 -0700)
committerRuss Cox <rsc@golang.org>
Thu, 14 Jul 2011 00:41:33 +0000 (17:41 -0700)
R=adg, rsc, bradfitz, mattn.jp, gustavo
CC=golang-dev
https://golang.org/cl/4625081

src/pkg/json/decode_test.go
src/pkg/json/encode.go
src/pkg/json/tagkey_test.go [new file with mode: 0644]

index 9b84bc76c477e1b44049cd206f8287f3d0da7854..24c97e576f99ebbe8faeda67203a185c57f3205d 100644 (file)
@@ -40,13 +40,6 @@ var (
        umtrue   = unmarshaler{true}
 )
 
-type badTag struct {
-       X string
-       Y string `json:"y"`
-       Z string `x:"@#*%(#@"`
-       W string `json:"@#$@#$"`
-}
-
 type unmarshalTest struct {
        in  string
        ptr interface{}
@@ -68,9 +61,6 @@ var unmarshalTests = []unmarshalTest{
        {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
        {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
 
-       // skip invalid tags
-       {`{"X":"a", "y":"b", "Z":"c", "W":"d"}`, new(badTag), badTag{"a", "b", "c", "d"}, nil},
-
        // syntax errors
        {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
 
index 3e4532cee4ea9ff16c174810428ec62e9bdd809b..fbc00355a6052e5c50f1ac2e1e51bd4c511c4dbc 100644 (file)
@@ -38,11 +38,11 @@ import (
 //
 // Struct values encode as JSON objects.  Each exported struct field
 // becomes a member of the object.  By default the object's key string
-// is the struct field name.  If the struct field's tag has a "json" key with a
-// value that is a non-empty string consisting of only Unicode letters,
-// digits, and underscores, that value will be used as the object key.
-// For example, the field tag `json:"myName"` says to use "myName"
-// as the object key.
+// is the struct field name.  If the struct field's tag has a "json"
+// key with a value that is a non-empty string consisting of only
+// Unicode letters, digits, dollar signs, hyphens, and underscores,
+// that value will be used as the object key.  For example, the field
+// tag `json:"myName"` says to use "myName" as the object key.
 //
 // Map values encode as JSON objects.
 // The map's key type must be string; the object keys are used directly
@@ -316,7 +316,7 @@ func isValidTag(s string) bool {
                return false
        }
        for _, c := range s {
-               if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+               if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
                        return false
                }
        }
diff --git a/src/pkg/json/tagkey_test.go b/src/pkg/json/tagkey_test.go
new file mode 100644 (file)
index 0000000..31fe2be
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json
+
+import (
+       "testing"
+)
+
+type basicLatin2xTag struct {
+       V string `json:"$-"`
+}
+
+type basicLatin3xTag struct {
+       V string `json:"0123456789"`
+}
+
+type basicLatin4xTag struct {
+       V string `json:"ABCDEFGHIJKLMO"`
+}
+
+type basicLatin5xTag struct {
+       V string `json:"PQRSTUVWXYZ_"`
+}
+
+type basicLatin6xTag struct {
+       V string `json:"abcdefghijklmno"`
+}
+
+type basicLatin7xTag struct {
+       V string `json:"pqrstuvwxyz"`
+}
+
+type miscPlaneTag struct {
+       V string `json:"色は匂へど"`
+}
+
+type emptyTag struct {
+       W string
+}
+
+type misnamedTag struct {
+       X string `jsom:"Misnamed"`
+}
+
+type badFormatTag struct {
+       Y string `:"BadFormat"`
+}
+
+type badCodeTag struct {
+       Z string `json:" !\"#%&'()*+,./"`
+}
+
+var structTagObjectKeyTests = []struct {
+       raw   interface{}
+       value string
+       key   string
+}{
+       {basicLatin2xTag{"2x"}, "2x", "$-"},
+       {basicLatin3xTag{"3x"}, "3x", "0123456789"},
+       {basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
+       {basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
+       {basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
+       {basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
+       {miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+       {emptyTag{"Pour Moi"}, "Pour Moi", "W"},
+       {misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
+       {badFormatTag{"Orfevre"}, "Orfevre", "Y"},
+       {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+}
+
+func TestStructTagObjectKey(t *testing.T) {
+       for _, tt := range structTagObjectKeyTests {
+               b, err := Marshal(tt.raw)
+               if err != nil {
+                       t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
+               }
+               var f interface{}
+               err = Unmarshal(b, &f)
+               if err != nil {
+                       t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
+               }
+               for i, v := range f.(map[string]interface{}) {
+                       switch i {
+                       case tt.key:
+                               if s, ok := v.(string); !ok || s != tt.value {
+                                       t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
+                               }
+                       default:
+                               t.Fatalf("Unexpected key: %#q", i)
+                       }
+               }
+       }
+}