Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
dba9d62b
Commit
dba9d62b
authored
Apr 21, 2010
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
json: Marshal, Unmarshal using new scanner
R=r CC=golang-dev
https://golang.org/cl/953041
parent
214a55b0
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
1547 additions
and
1030 deletions
+1547
-1030
src/pkg/expvar/expvar.go
src/pkg/expvar/expvar.go
+4
-7
src/pkg/expvar/expvar_test.go
src/pkg/expvar/expvar_test.go
+2
-1
src/pkg/json/Makefile
src/pkg/json/Makefile
+1
-1
src/pkg/json/decode.go
src/pkg/json/decode.go
+855
-63
src/pkg/json/decode_test.go
src/pkg/json/decode_test.go
+391
-97
src/pkg/json/encode.go
src/pkg/json/encode.go
+282
-0
src/pkg/json/scanner.go
src/pkg/json/scanner.go
+5
-1
src/pkg/json/scanner_test.go
src/pkg/json/scanner_test.go
+6
-3
src/pkg/json/struct.go
src/pkg/json/struct.go
+0
-481
src/pkg/json/struct_test.go
src/pkg/json/struct_test.go
+0
-375
src/pkg/template/template_test.go
src/pkg/template/template_test.go
+1
-1
No files found.
src/pkg/expvar/expvar.go
View file @
dba9d62b
...
@@ -225,16 +225,13 @@ func expvarHandler(c *http.Conn, req *http.Request) {
...
@@ -225,16 +225,13 @@ func expvarHandler(c *http.Conn, req *http.Request) {
}
}
func
memstats
()
string
{
func
memstats
()
string
{
var
buf
bytes
.
Buffer
b
,
_
:=
json
.
MarshalIndent
(
&
runtime
.
MemStats
,
""
,
"
\t
"
)
json
.
MarshalIndent
(
&
buf
,
&
runtime
.
MemStats
,
" "
)
return
string
(
b
)
s
:=
buf
.
String
()
return
s
[
0
:
len
(
s
)
-
1
]
// chop final \n
}
}
func
cmdline
()
string
{
func
cmdline
()
string
{
var
buf
bytes
.
Buffer
b
,
_
:=
json
.
Marshal
(
os
.
Args
)
json
.
Marshal
(
&
buf
,
os
.
Args
)
return
string
(
b
)
return
buf
.
String
()
}
}
func
init
()
{
func
init
()
{
...
...
src/pkg/expvar/expvar_test.go
View file @
dba9d62b
...
@@ -61,7 +61,8 @@ func TestMapCounter(t *testing.T) {
...
@@ -61,7 +61,8 @@ func TestMapCounter(t *testing.T) {
// colours.String() should be '{"red":3, "blue":4}',
// colours.String() should be '{"red":3, "blue":4}',
// though the order of red and blue could vary.
// though the order of red and blue could vary.
s
:=
colours
.
String
()
s
:=
colours
.
String
()
j
,
err
:=
json
.
Decode
(
s
)
var
j
interface
{}
err
:=
json
.
Unmarshal
([]
byte
(
s
),
&
j
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"colours.String() isn't valid JSON: %v"
,
err
)
t
.
Errorf
(
"colours.String() isn't valid JSON: %v"
,
err
)
}
}
...
...
src/pkg/json/Makefile
View file @
dba9d62b
...
@@ -7,10 +7,10 @@ include ../../Make.$(GOARCH)
...
@@ -7,10 +7,10 @@ include ../../Make.$(GOARCH)
TARG
=
json
TARG
=
json
GOFILES
=
\
GOFILES
=
\
decode.go
\
decode.go
\
encode.go
\
error.go
\
error.go
\
indent.go
\
indent.go
\
parse.go
\
parse.go
\
scanner.go
\
scanner.go
\
struct.go
\
include
../../Make.pkg
include
../../Make.pkg
src/pkg/json/decode.go
View file @
dba9d62b
// Copyright 20
09
The Go Authors. All rights reserved.
// Copyright 20
10
The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// license that can be found in the LICENSE file.
...
@@ -10,96 +10,888 @@ package json
...
@@ -10,96 +10,888 @@ package json
import
(
import
(
"container/vector"
"container/vector"
"os"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"unicode"
"utf16"
"utf8"
)
)
// Decode a JSON string
// Unmarshal parses the JSON-encoded data and stores the result
// in the value pointed at by v.
// Decode parses the string s as a JSON-syntax string and returns the
// generic JSON object representation. The object representation is a tree
// of Go data types. The data return value may be one of float64, string,
// bool, nil, []interface{} or map[string]interface{}. The array and map
// elements may in turn contain any of the types listed above and so on.
//
//
// If Decode encounters a syntax error, it returns with err set to an
// Unmarshal traverses the value v recursively.
// instance of ParseError. See ParseError documentation for details.
// If an encountered value implements the Unmarshaler interface,
func
Decode
(
s
string
)
(
data
interface
{},
err
os
.
Error
)
{
// Unmarshal calls its UnmarshalJSON method with a well-formed
jb
:=
newDecoder
(
nil
,
nil
)
// JSON encoding.
ok
,
errPos
,
errTok
:=
Parse
(
s
,
jb
)
//
if
ok
{
// Otherwise, Unmarshal uses the inverse of the encodings that
data
=
jb
.
Data
()
// Marshal uses, allocating maps, slices, and pointers as necessary,
}
else
{
// with the following additional rules:
err
=
&
ParseError
{
Index
:
errPos
,
Token
:
errTok
}
//
// To unmarshal a JSON value into a nil interface value, the
// type stored in the interface value is one of:
//
// bool, for JSON booleans
// float64, for JSON numbers
// string, for JSON strings
// []interface{}, for JSON arrays
// map[string]interface{}, for JSON objects
// nil for JSON null
//
// If a JSON value is not appropriate for a given target type,
// or if a JSON number overflows the target type, Unmarshal
// skips that field and completes the unmarshalling as best it can.
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
func
Unmarshal
(
data
[]
byte
,
v
interface
{})
os
.
Error
{
d
:=
new
(
decodeState
)
.
init
(
data
)
// Quick check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
err
:=
checkValid
(
data
,
&
d
.
scan
)
if
err
!=
nil
{
return
err
}
}
return
return
d
.
unmarshal
(
v
)
}
}
type
decoder
struct
{
// Unmarshaler is the interface implemented by objects
// A value being constructed.
// that can unmarshal a JSON description of themselves.
value
interface
{}
// The input can be assumed to be a valid JSON object
// Container entity to flush into. Can be either vector.Vector or
// encoding. UnmarshalJSON must copy the JSON data
// map[string]interface{}.
// if it wishes to retain the data after returning.
container
interface
{}
type
Unmarshaler
interface
{
// The index into the container interface. Either int or string.
UnmarshalJSON
([]
byte
)
os
.
Error
index
interface
{}
}
}
func
newDecoder
(
container
interface
{},
key
interface
{})
*
decoder
{
return
&
decoder
{
container
:
container
,
index
:
key
}
// An UnmarshalTypeError describes a JSON value that was
// not appropriate for a value of a specific Go type.
type
UnmarshalTypeError
struct
{
Value
string
// description of JSON value - "bool", "array", "number -5"
Type
reflect
.
Type
// type of Go value it could not be assigned to
}
}
func
(
j
*
decoder
)
Int64
(
i
int64
)
{
j
.
value
=
float64
(
i
)
}
func
(
e
*
UnmarshalTypeError
)
String
()
string
{
return
"json: cannot unmarshal "
+
e
.
Value
+
" into Go value of type "
+
e
.
Type
.
String
()
}
func
(
j
*
decoder
)
Uint64
(
i
uint64
)
{
j
.
value
=
float64
(
i
)
}
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)
type
InvalidUnmarshalError
struct
{
Type
reflect
.
Type
}
func
(
j
*
decoder
)
Float64
(
f
float64
)
{
j
.
value
=
float64
(
f
)
}
func
(
e
*
InvalidUnmarshalError
)
String
()
string
{
if
e
.
Type
==
nil
{
return
"json: Unmarshal(nil)"
}
func
(
j
*
decoder
)
String
(
s
string
)
{
j
.
value
=
s
}
if
_
,
ok
:=
e
.
Type
.
(
*
reflect
.
PtrType
);
!
ok
{
return
"json: Unmarshal(non-pointer "
+
e
.
Type
.
String
()
+
")"
}
return
"json: Unmarshal(nil "
+
e
.
Type
.
String
()
+
")"
}
func
(
j
*
decoder
)
Bool
(
b
bool
)
{
j
.
value
=
b
}
func
(
d
*
decodeState
)
unmarshal
(
v
interface
{})
(
err
os
.
Error
)
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
if
_
,
ok
:=
r
.
(
runtime
.
Error
);
ok
{
panic
(
r
)
}
err
=
r
.
(
os
.
Error
)
}
}()
func
(
j
*
decoder
)
Null
()
{
j
.
value
=
nil
}
rv
:=
reflect
.
NewValue
(
v
)
pv
,
ok
:=
rv
.
(
*
reflect
.
PtrValue
)
if
!
ok
||
pv
.
IsNil
()
{
return
&
InvalidUnmarshalError
{
reflect
.
Typeof
(
v
)}
}
func
(
j
*
decoder
)
Array
()
{
j
.
value
=
new
(
vector
.
Vector
)
}
d
.
scan
.
reset
()
d
.
value
(
pv
.
Elem
())
return
d
.
savedError
}
func
(
j
*
decoder
)
Map
()
{
j
.
value
=
make
(
map
[
string
]
interface
{})
}
// decodeState represents the state while decoding a JSON value.
type
decodeState
struct
{
data
[]
byte
off
int
// read offset in data
scan
scanner
nextscan
scanner
// for calls to nextValue
savedError
os
.
Error
}
func
(
j
*
decoder
)
Elem
(
i
int
)
Builder
{
// errPhase is used for errors that should not happen unless
v
,
ok
:=
j
.
value
.
(
*
vector
.
Vector
)
// there is a bug in the JSON decoder or something is editing
if
!
ok
{
// the data slice while the decoder executes.
v
=
new
(
vector
.
Vector
)
var
errPhase
=
os
.
NewError
(
"JSON decoder out of sync - data changing underfoot?"
)
j
.
value
=
v
func
(
d
*
decodeState
)
init
(
data
[]
byte
)
*
decodeState
{
d
.
data
=
data
d
.
off
=
0
d
.
savedError
=
nil
return
d
}
// error aborts the decoding by panicking with err.
func
(
d
*
decodeState
)
error
(
err
os
.
Error
)
{
panic
(
err
)
}
// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
func
(
d
*
decodeState
)
saveError
(
err
os
.
Error
)
{
if
d
.
savedError
==
nil
{
d
.
savedError
=
err
}
}
// next cuts off and returns the next full JSON value in d.data[d.off:].
// The next value is known to be an object or array, not a literal.
func
(
d
*
decodeState
)
next
()
[]
byte
{
c
:=
d
.
data
[
d
.
off
]
item
,
rest
,
err
:=
nextValue
(
d
.
data
[
d
.
off
:
],
&
d
.
nextscan
)
if
err
!=
nil
{
d
.
error
(
err
)
}
d
.
off
=
len
(
d
.
data
)
-
len
(
rest
)
// Our scanner has seen the opening brace/bracket
// and thinks we're still in the middle of the object.
// invent a closing brace/bracket to get it out.
if
c
==
'{'
{
d
.
scan
.
step
(
&
d
.
scan
,
'}'
)
}
else
{
d
.
scan
.
step
(
&
d
.
scan
,
']'
)
}
}
if
v
.
Len
()
<=
i
{
v
.
Resize
(
i
+
1
,
(
i
+
1
)
*
2
)
return
item
}
// scanWhile processes bytes in d.data[d.off:] until it
// receives a scan code not equal to op.
// It updates d.off and returns the new scan code.
func
(
d
*
decodeState
)
scanWhile
(
op
int
)
int
{
var
newOp
int
for
{
if
d
.
off
>=
len
(
d
.
data
)
{
newOp
=
d
.
scan
.
eof
()
d
.
off
=
len
(
d
.
data
)
+
1
// mark processed EOF with len+1
}
else
{
c
:=
int
(
d
.
data
[
d
.
off
])
d
.
off
++
newOp
=
d
.
scan
.
step
(
&
d
.
scan
,
c
)
}
if
newOp
!=
op
{
break
}
}
return
newOp
}
// value decodes a JSON value from d.data[d.off:] into the value.
// it updates d.off to point past the decoded value.
func
(
d
*
decodeState
)
value
(
v
reflect
.
Value
)
{
if
v
==
nil
{
_
,
rest
,
err
:=
nextValue
(
d
.
data
[
d
.
off
:
],
&
d
.
nextscan
)
if
err
!=
nil
{
d
.
error
(
err
)
}
d
.
off
=
len
(
d
.
data
)
-
len
(
rest
)
// d.scan thinks we're still at the beginning of the item.
// Feed in an empty string - the shortest, simplest value -
// so that it knows we got to the end of the value.
if
d
.
scan
.
step
==
stateRedo
{
panic
(
"redo"
)
}
d
.
scan
.
step
(
&
d
.
scan
,
'"'
)
d
.
scan
.
step
(
&
d
.
scan
,
'"'
)
return
}
switch
op
:=
d
.
scanWhile
(
scanSkipSpace
);
op
{
default
:
d
.
error
(
errPhase
)
case
scanBeginArray
:
d
.
array
(
v
)
case
scanBeginObject
:
d
.
object
(
v
)
case
scanBeginLiteral
:
d
.
literal
(
v
)
}
}
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
// if wantptr is true, indirect stops at the last pointer.
func
(
d
*
decodeState
)
indirect
(
v
reflect
.
Value
,
wantptr
bool
)
(
Unmarshaler
,
reflect
.
Value
)
{
for
{
var
isUnmarshaler
bool
if
v
.
Type
()
.
NumMethod
()
>
0
{
// Remember that this is an unmarshaler,
// but wait to return it until after allocating
// the pointer (if necessary).
_
,
isUnmarshaler
=
v
.
Interface
()
.
(
Unmarshaler
)
}
pv
,
ok
:=
v
.
(
*
reflect
.
PtrValue
)
if
!
ok
{
break
}
_
,
isptrptr
:=
pv
.
Elem
()
.
(
*
reflect
.
PtrValue
)
if
!
isptrptr
&&
wantptr
&&
!
isUnmarshaler
{
return
nil
,
pv
}
pv
.
PointTo
(
reflect
.
MakeZero
(
pv
.
Type
()
.
(
*
reflect
.
PtrType
)
.
Elem
()))
if
isUnmarshaler
{
// Using v.Interface().(Unmarshaler)
// here means that we have to use a pointer
// as the struct field. We cannot use a value inside
// a pointer to a struct, because in that case
// v.Interface() is the value (x.f) not the pointer (&x.f).
// This is an unfortunate consequence of reflect.
// An alternative would be to look up the
// UnmarshalJSON method and return a FuncValue.
return
v
.
Interface
()
.
(
Unmarshaler
),
nil
}
v
=
pv
.
Elem
()
}
}
return
n
ewDecoder
(
v
,
i
)
return
n
il
,
v
}
}
func
(
j
*
decoder
)
Key
(
s
string
)
Builder
{
// array consumes an array from d.data[d.off-1:], decoding into the value v.
m
,
ok
:=
j
.
value
.
(
map
[
string
]
interface
{})
// the first byte of the array ('[') has been read already.
func
(
d
*
decodeState
)
array
(
v
reflect
.
Value
)
{
// Check for unmarshaler.
unmarshaler
,
pv
:=
d
.
indirect
(
v
,
false
)
if
unmarshaler
!=
nil
{
d
.
off
--
err
:=
unmarshaler
.
UnmarshalJSON
(
d
.
next
())
if
err
!=
nil
{
d
.
error
(
err
)
}
return
}
v
=
pv
// Decoding into nil interface? Switch to non-reflect code.
iv
,
ok
:=
v
.
(
*
reflect
.
InterfaceValue
)
if
ok
{
iv
.
Set
(
reflect
.
NewValue
(
d
.
arrayInterface
()))
return
}
// Check type of target.
av
,
ok
:=
v
.
(
reflect
.
ArrayOrSliceValue
)
if
!
ok
{
if
!
ok
{
m
=
make
(
map
[
string
]
interface
{})
d
.
saveError
(
&
UnmarshalTypeError
{
"array"
,
v
.
Type
()})
j
.
value
=
m
}
sv
,
_
:=
v
.
(
*
reflect
.
SliceValue
)
i
:=
0
for
{
// Look ahead for ] - can only happen on first iteration.
op
:=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndArray
{
break
}
// Back up so d.value can have the byte we just read.
d
.
off
--
d
.
scan
.
undo
(
op
)
// Get element of array, growing if necessary.
if
i
>=
av
.
Cap
()
&&
sv
!=
nil
{
newcap
:=
sv
.
Cap
()
+
sv
.
Cap
()
/
2
if
newcap
<
4
{
newcap
=
4
}
newv
:=
reflect
.
MakeSlice
(
sv
.
Type
()
.
(
*
reflect
.
SliceType
),
sv
.
Len
(),
newcap
)
reflect
.
ArrayCopy
(
newv
,
sv
)
sv
.
Set
(
newv
)
}
if
i
>=
av
.
Len
()
&&
sv
!=
nil
{
// Must be slice; gave up on array during i >= av.Cap().
sv
.
SetLen
(
i
+
1
)
}
// Decode into element.
if
i
<
av
.
Len
()
{
d
.
value
(
av
.
Elem
(
i
))
}
else
{
// Ran out of fixed array: skip.
d
.
value
(
nil
)
}
i
++
// Next token must be , or ].
op
=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndArray
{
break
}
if
op
!=
scanArrayValue
{
d
.
error
(
errPhase
)
}
}
if
i
<
av
.
Len
()
{
if
sv
==
nil
{
// Array. Zero the rest.
z
:=
reflect
.
MakeZero
(
av
.
Type
()
.
(
*
reflect
.
ArrayType
)
.
Elem
())
for
;
i
<
av
.
Len
();
i
++
{
av
.
Elem
(
i
)
.
SetValue
(
z
)
}
}
else
{
sv
.
SetLen
(
i
)
}
}
}
// matchName returns true if key should be written to a field named name.
func
matchName
(
key
,
name
string
)
bool
{
return
strings
.
ToLower
(
key
)
==
strings
.
ToLower
(
name
)
}
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte of the object ('{') has been read already.
func
(
d
*
decodeState
)
object
(
v
reflect
.
Value
)
{
// Check for unmarshaler.
unmarshaler
,
pv
:=
d
.
indirect
(
v
,
false
)
if
unmarshaler
!=
nil
{
d
.
off
--
err
:=
unmarshaler
.
UnmarshalJSON
(
d
.
next
())
if
err
!=
nil
{
d
.
error
(
err
)
}
return
}
v
=
pv
// Decoding into nil interface? Switch to non-reflect code.
iv
,
ok
:=
v
.
(
*
reflect
.
InterfaceValue
)
if
ok
{
iv
.
Set
(
reflect
.
NewValue
(
d
.
objectInterface
()))
return
}
// Check type of target: struct or map[string]T
var
(
mv
*
reflect
.
MapValue
sv
*
reflect
.
StructValue
)
switch
v
:=
v
.
(
type
)
{
case
*
reflect
.
MapValue
:
// map must have string type
t
:=
v
.
Type
()
.
(
*
reflect
.
MapType
)
if
t
.
Key
()
!=
reflect
.
Typeof
(
""
)
{
d
.
saveError
(
&
UnmarshalTypeError
{
"object"
,
v
.
Type
()})
break
}
mv
=
v
if
mv
.
IsNil
()
{
mv
.
SetValue
(
reflect
.
MakeMap
(
t
))
}
case
*
reflect
.
StructValue
:
sv
=
v
default
:
d
.
saveError
(
&
UnmarshalTypeError
{
"object"
,
v
.
Type
()})
}
if
mv
==
nil
&&
sv
==
nil
{
d
.
off
--
d
.
next
()
// skip over { } in input
return
}
for
{
// Read opening " of string key or closing }.
op
:=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndObject
{
// closing } - can only happen on first iteration.
break
}
if
op
!=
scanBeginLiteral
{
d
.
error
(
errPhase
)
}
// Read string key.
start
:=
d
.
off
-
1
op
=
d
.
scanWhile
(
scanContinue
)
item
:=
d
.
data
[
start
:
d
.
off
-
1
]
key
,
ok
:=
unquote
(
item
)
if
!
ok
{
d
.
error
(
errPhase
)
}
// Figure out
var
subv
reflect
.
Value
if
mv
!=
nil
{
subv
=
reflect
.
MakeZero
(
mv
.
Type
()
.
(
*
reflect
.
MapType
)
.
Elem
())
}
else
{
for
i
:=
0
;
i
<
sv
.
NumField
();
i
++
{
f
:=
sv
.
Type
()
.
(
*
reflect
.
StructType
)
.
Field
(
i
)
if
f
.
Tag
==
key
{
subv
=
sv
.
Field
(
i
)
break
}
}
if
subv
==
nil
{
subv
=
sv
.
FieldByNameFunc
(
func
(
s
string
)
bool
{
return
matchName
(
key
,
s
)
})
}
}
// Read : before value.
if
op
==
scanSkipSpace
{
op
=
d
.
scanWhile
(
scanSkipSpace
)
}
if
op
!=
scanObjectKey
{
d
.
error
(
errPhase
)
}
// Read value.
d
.
value
(
subv
)
// Write value back to map;
// if using struct, subv points into struct already.
if
mv
!=
nil
{
mv
.
SetElem
(
reflect
.
NewValue
(
key
),
subv
)
}
// Next token must be , or }.
op
=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndObject
{
break
}
if
op
!=
scanObjectValue
{
d
.
error
(
errPhase
)
}
}
}
// literal consumes a literal from d.data[d.off-1:], decoding into the value v.
// The first byte of the literal has been read already
// (that's how the caller knows it's a literal).
func
(
d
*
decodeState
)
literal
(
v
reflect
.
Value
)
{
// All bytes inside literal return scanContinue op code.
start
:=
d
.
off
-
1
op
:=
d
.
scanWhile
(
scanContinue
)
// Scan read one byte too far; back up.
d
.
off
--
d
.
scan
.
undo
(
op
)
item
:=
d
.
data
[
start
:
d
.
off
]
// Check for unmarshaler.
wantptr
:=
item
[
0
]
==
'n'
// null
unmarshaler
,
pv
:=
d
.
indirect
(
v
,
wantptr
)
if
unmarshaler
!=
nil
{
err
:=
unmarshaler
.
UnmarshalJSON
(
item
)
if
err
!=
nil
{
d
.
error
(
err
)
}
return
}
v
=
pv
switch
c
:=
item
[
0
];
c
{
case
'n'
:
// null
switch
v
.
(
type
)
{
default
:
d
.
saveError
(
&
UnmarshalTypeError
{
"null"
,
v
.
Type
()})
case
*
reflect
.
InterfaceValue
,
*
reflect
.
PtrValue
,
*
reflect
.
MapValue
:
v
.
SetValue
(
nil
)
}
case
't'
,
'f'
:
// true, false
value
:=
c
==
't'
switch
v
:=
v
.
(
type
)
{
default
:
d
.
saveError
(
&
UnmarshalTypeError
{
"bool"
,
v
.
Type
()})
case
*
reflect
.
BoolValue
:
v
.
Set
(
value
)
case
*
reflect
.
InterfaceValue
:
v
.
Set
(
reflect
.
NewValue
(
value
))
}
case
'"'
:
// string
s
,
ok
:=
unquote
(
item
)
if
!
ok
{
d
.
error
(
errPhase
)
}
switch
v
:=
v
.
(
type
)
{
default
:
d
.
saveError
(
&
UnmarshalTypeError
{
"string"
,
v
.
Type
()})
case
*
reflect
.
StringValue
:
v
.
Set
(
s
)
case
*
reflect
.
InterfaceValue
:
v
.
Set
(
reflect
.
NewValue
(
s
))
}
default
:
// number
if
c
!=
'-'
&&
(
c
<
'0'
||
c
>
'9'
)
{
d
.
error
(
errPhase
)
}
s
:=
string
(
item
)
switch
v
:=
v
.
(
type
)
{
default
:
d
.
error
(
&
UnmarshalTypeError
{
"number"
,
v
.
Type
()})
case
*
reflect
.
InterfaceValue
:
n
,
err
:=
strconv
.
Atof64
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
reflect
.
NewValue
(
n
))
case
*
reflect
.
IntValue
:
n
,
err
:=
strconv
.
Atoi
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
Int8Value
:
n
,
err
:=
strconv
.
Atoi
(
s
)
if
err
!=
nil
||
int
(
int8
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
int8
(
n
))
case
*
reflect
.
Int16Value
:
n
,
err
:=
strconv
.
Atoi
(
s
)
if
err
!=
nil
||
int
(
int16
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
int16
(
n
))
case
*
reflect
.
Int32Value
:
n
,
err
:=
strconv
.
Atoi
(
s
)
if
err
!=
nil
||
int
(
int32
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
int32
(
n
))
case
*
reflect
.
Int64Value
:
n
,
err
:=
strconv
.
Atoi64
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
UintValue
:
n
,
err
:=
strconv
.
Atoui
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
Uint8Value
:
n
,
err
:=
strconv
.
Atoui
(
s
)
if
err
!=
nil
||
uint
(
uint8
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
uint8
(
n
))
case
*
reflect
.
Uint16Value
:
n
,
err
:=
strconv
.
Atoui
(
s
)
if
err
!=
nil
||
uint
(
uint16
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
uint16
(
n
))
case
*
reflect
.
Uint32Value
:
n
,
err
:=
strconv
.
Atoui
(
s
)
if
err
!=
nil
||
uint
(
uint32
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
uint32
(
n
))
case
*
reflect
.
Uint64Value
:
n
,
err
:=
strconv
.
Atoui64
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
UintptrValue
:
n
,
err
:=
strconv
.
Atoui64
(
s
)
if
err
!=
nil
||
uint64
(
uintptr
(
n
))
!=
n
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
uintptr
(
n
))
case
*
reflect
.
FloatValue
:
n
,
err
:=
strconv
.
Atof
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
Float32Value
:
n
,
err
:=
strconv
.
Atof32
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
case
*
reflect
.
Float64Value
:
n
,
err
:=
strconv
.
Atof64
(
s
)
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
s
,
v
.
Type
()})
break
}
v
.
Set
(
n
)
}
}
}
return
newDecoder
(
m
,
s
)
}
}
func
(
j
*
decoder
)
Flush
()
{
// The xxxInterface routines build up a value to be stored
switch
c
:=
j
.
container
.
(
type
)
{
// in an empty interface. They are not strictly necessary,
case
*
vector
.
Vector
:
// but they avoid the weight of reflection in this common case.
index
:=
j
.
index
.
(
int
)
c
.
Set
(
index
,
j
.
Data
())
// valueInterface is like value but returns interface{}
case
map
[
string
]
interface
{}
:
func
(
d
*
decodeState
)
valueInterface
()
interface
{}
{
index
:=
j
.
index
.
(
string
)
switch
d
.
scanWhile
(
scanSkipSpace
)
{
c
[
index
]
=
j
.
Data
()
default
:
d
.
error
(
errPhase
)
case
scanBeginArray
:
return
d
.
arrayInterface
()
case
scanBeginObject
:
return
d
.
objectInterface
()
case
scanBeginLiteral
:
return
d
.
literalInterface
()
}
panic
(
"unreachable"
)
}
// arrayInterface is like array but returns []interface{}.
func
(
d
*
decodeState
)
arrayInterface
()
[]
interface
{}
{
var
v
vector
.
Vector
for
{
// Look ahead for ] - can only happen on first iteration.
op
:=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndArray
{
break
}
// Back up so d.value can have the byte we just read.
d
.
off
--
d
.
scan
.
undo
(
op
)
v
.
Push
(
d
.
valueInterface
())
// Next token must be , or ].
op
=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndArray
{
break
}
if
op
!=
scanArrayValue
{
d
.
error
(
errPhase
)
}
}
return
v
}
// objectInterface is like object but returns map[string]interface{}.
func
(
d
*
decodeState
)
objectInterface
()
map
[
string
]
interface
{}
{
m
:=
make
(
map
[
string
]
interface
{})
for
{
// Read opening " of string key or closing }.
op
:=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndObject
{
// closing } - can only happen on first iteration.
break
}
if
op
!=
scanBeginLiteral
{
d
.
error
(
errPhase
)
}
// Read string key.
start
:=
d
.
off
-
1
op
=
d
.
scanWhile
(
scanContinue
)
item
:=
d
.
data
[
start
:
d
.
off
-
1
]
key
,
ok
:=
unquote
(
item
)
if
!
ok
{
d
.
error
(
errPhase
)
}
// Read : before value.
if
op
==
scanSkipSpace
{
op
=
d
.
scanWhile
(
scanSkipSpace
)
}
if
op
!=
scanObjectKey
{
d
.
error
(
errPhase
)
}
// Read value.
m
[
key
]
=
d
.
valueInterface
()
// Next token must be , or }.
op
=
d
.
scanWhile
(
scanSkipSpace
)
if
op
==
scanEndObject
{
break
}
if
op
!=
scanObjectValue
{
d
.
error
(
errPhase
)
}
}
}
return
m
}
}
// Get the value built by this builder.
func
(
j
*
decoder
)
Data
()
interface
{}
{
// literalInterface is like literal but returns an interface value.
switch
v
:=
j
.
value
.
(
type
)
{
func
(
d
*
decodeState
)
literalInterface
()
interface
{}
{
case
*
vector
.
Vector
:
// All bytes inside literal return scanContinue op code.
return
v
.
Data
()
start
:=
d
.
off
-
1
op
:=
d
.
scanWhile
(
scanContinue
)
// Scan read one byte too far; back up.
d
.
off
--
d
.
scan
.
undo
(
op
)
item
:=
d
.
data
[
start
:
d
.
off
]
switch
c
:=
item
[
0
];
c
{
case
'n'
:
// null
return
nil
case
't'
,
'f'
:
// true, false
return
c
==
't'
case
'"'
:
// string
s
,
ok
:=
unquote
(
item
)
if
!
ok
{
d
.
error
(
errPhase
)
}
return
s
default
:
// number
if
c
!=
'-'
&&
(
c
<
'0'
||
c
>
'9'
)
{
d
.
error
(
errPhase
)
}
n
,
err
:=
strconv
.
Atof64
(
string
(
item
))
if
err
!=
nil
{
d
.
saveError
(
&
UnmarshalTypeError
{
"number "
+
string
(
item
),
reflect
.
Typeof
(
float64
(
0
))})
}
return
n
}
panic
(
"unreachable"
)
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
// or it returns -1.
func
getu4
(
s
[]
byte
)
int
{
if
len
(
s
)
<
6
||
s
[
0
]
!=
'\\'
||
s
[
1
]
!=
'u'
{
return
-
1
}
rune
,
err
:=
strconv
.
Btoui64
(
string
(
s
[
2
:
6
]),
16
)
if
err
!=
nil
{
return
-
1
}
return
int
(
rune
)
}
// unquote converts a quoted JSON string literal s into an actual string t.
// The rules are different than for Go, so cannot use strconv.Unquote.
func
unquote
(
s
[]
byte
)
(
t
string
,
ok
bool
)
{
if
len
(
s
)
<
2
||
s
[
0
]
!=
'"'
||
s
[
len
(
s
)
-
1
]
!=
'"'
{
return
}
b
:=
make
([]
byte
,
len
(
s
)
+
2
*
utf8
.
UTFMax
)
w
:=
0
for
r
:=
1
;
r
<
len
(
s
)
-
1
;
{
// Out of room? Can only happen if s is full of
// malformed UTF-8 and we're replacing each
// byte with RuneError.
if
w
>=
len
(
b
)
-
2
*
utf8
.
UTFMax
{
nb
:=
make
([]
byte
,
(
len
(
b
)
+
utf8
.
UTFMax
)
*
2
)
copy
(
nb
,
b
[
0
:
w
])
b
=
nb
}
switch
c
:=
s
[
r
];
{
case
c
==
'\\'
:
r
++
if
r
>=
len
(
s
)
-
1
{
return
}
switch
s
[
r
]
{
default
:
return
case
'"'
,
'\\'
,
'/'
,
'\'
'
:
b
[
w
]
=
s
[
r
]
r
++
w
++
case
'b'
:
b
[
w
]
=
'\b'
r
++
w
++
case
'f'
:
b
[
w
]
=
'\f'
r
++
w
++
case
'n'
:
b
[
w
]
=
'\n'
r
++
w
++
case
'r'
:
b
[
w
]
=
'\r'
r
++
w
++
case
't'
:
b
[
w
]
=
'\t'
r
++
w
++
case
'u'
:
r
--
rune
:=
getu4
(
s
[
r
:
])
if
rune
<
0
{
return
}
r
+=
6
if
utf16
.
IsSurrogate
(
rune
)
{
rune1
:=
getu4
(
s
[
r
:
])
if
dec
:=
utf16
.
DecodeRune
(
rune
,
rune1
);
dec
!=
unicode
.
ReplacementChar
{
// A valid pair; consume.
r
+=
6
w
+=
utf8
.
EncodeRune
(
dec
,
b
[
w
:
])
break
}
// Invalid surrogate; fall back to replacement rune.
rune
=
unicode
.
ReplacementChar
}
w
+=
utf8
.
EncodeRune
(
rune
,
b
[
w
:
])
}
// Quote, control characters are invalid.
case
c
==
'"'
,
c
<
' '
:
return
// ASCII
case
c
<
utf8
.
RuneSelf
:
b
[
w
]
=
c
r
++
w
++
// Coerce to well-formed UTF-8.
default
:
rune
,
size
:=
utf8
.
DecodeRune
(
s
[
r
:
])
r
+=
size
w
+=
utf8
.
EncodeRune
(
rune
,
b
[
w
:
])
}
}
}
return
j
.
val
ue
return
string
(
b
[
0
:
w
]),
tr
ue
}
}
src/pkg/json/decode_test.go
View file @
dba9d62b
// Copyright 20
09
The Go Authors. All rights reserved.
// Copyright 20
10
The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// license that can be found in the LICENSE file.
package
json
package
json
import
(
import
(
"
container/vector
"
"
bytes
"
"reflect"
"reflect"
"strings"
"testing"
"testing"
)
)
func
TestDecodeInt64
(
t
*
testing
.
T
)
{
type
unmarshalTest
struct
{
nb
:=
newDecoder
(
nil
,
nil
)
in
string
nb
.
Int64
(
-
15
)
ptr
interface
{}
assertResult
(
t
,
nb
.
Data
(),
float64
(
-
15
))
out
interface
{}
}
}
func
TestDecodeUint64
(
t
*
testing
.
T
)
{
var
unmarshalTests
=
[]
unmarshalTest
{
nb
:=
newDecoder
(
nil
,
nil
)
// basic types
nb
.
Uint64
(
15
)
unmarshalTest
{
`true`
,
new
(
bool
),
true
},
assertResult
(
t
,
nb
.
Data
(),
float64
(
15
))
unmarshalTest
{
`1`
,
new
(
int
),
1
},
}
unmarshalTest
{
`1.2`
,
new
(
float
),
1.2
},
unmarshalTest
{
`-5`
,
new
(
int16
),
int16
(
-
5
)},
unmarshalTest
{
`"a\u1234"`
,
new
(
string
),
"a
\u1234
"
},
unmarshalTest
{
`"g-clef: \uD834\uDD1E"`
,
new
(
string
),
"g-clef:
\U0001D11E
"
},
unmarshalTest
{
`"invalid: \uD834x\uDD1E"`
,
new
(
string
),
"invalid:
\uFFFD
x
\uFFFD
"
},
unmarshalTest
{
"null"
,
new
(
interface
{}),
nil
},
func
TestDecodeFloat64
(
t
*
testing
.
T
)
{
// composite tests
nb
:=
newDecoder
(
nil
,
nil
)
unmarshalTest
{
allValueIndent
,
new
(
All
),
allValue
},
nb
.
Float64
(
3.14159
)
unmarshalTest
{
allValueCompact
,
new
(
All
),
allValue
},
assertResult
(
t
,
nb
.
Data
(),
float64
(
3.14159
))
unmarshalTest
{
allValueIndent
,
new
(
*
All
),
&
allValue
},
unmarshalTest
{
allValueCompact
,
new
(
*
All
),
&
allValue
},
unmarshalTest
{
pallValueIndent
,
new
(
All
),
pallValue
},
unmarshalTest
{
pallValueCompact
,
new
(
All
),
pallValue
},
unmarshalTest
{
pallValueIndent
,
new
(
*
All
),
&
pallValue
},
unmarshalTest
{
pallValueCompact
,
new
(
*
All
),
&
pallValue
},
}
}
func
TestDecodeString
(
t
*
testing
.
T
)
{
func
TestMarshal
(
t
*
testing
.
T
)
{
nb
:=
newDecoder
(
nil
,
nil
)
b
,
err
:=
Marshal
(
allValue
)
nb
.
String
(
"Some string"
)
if
err
!=
nil
{
assertResult
(
t
,
nb
.
Data
(),
"Some string"
)
t
.
Fatalf
(
"Marshal allValue: %v"
,
err
)
}
}
if
string
(
b
)
!=
allValueCompact
{
t
.
Errorf
(
"Marshal allValueCompact"
)
diff
(
t
,
b
,
[]
byte
(
allValueCompact
))
return
}
func
TestDecodeBool
(
t
*
testing
.
T
)
{
b
,
err
=
Marshal
(
pallValue
)
nb
:=
newDecoder
(
nil
,
nil
)
if
err
!=
nil
{
nb
.
Bool
(
true
)
t
.
Fatalf
(
"Marshal pallValue: %v"
,
err
)
assertResult
(
t
,
nb
.
Data
(),
true
)
}
if
string
(
b
)
!=
pallValueCompact
{
t
.
Errorf
(
"Marshal pallValueCompact"
)
diff
(
t
,
b
,
[]
byte
(
pallValueCompact
))
return
}
}
}
func
TestDecodeNull
(
t
*
testing
.
T
)
{
func
TestUnmarshal
(
t
*
testing
.
T
)
{
nb
:=
newDecoder
(
nil
,
nil
)
var
scan
scanner
nb
.
Null
()
for
i
,
tt
:=
range
unmarshalTests
{
assertResult
(
t
,
nb
.
Data
(),
nil
)
in
:=
[]
byte
(
tt
.
in
)
if
err
:=
checkValid
(
in
,
&
scan
);
err
!=
nil
{
t
.
Errorf
(
"#%d: checkValid: %v"
,
i
,
err
)
continue
}
// v = new(right-type)
v
:=
reflect
.
NewValue
(
tt
.
ptr
)
.
(
*
reflect
.
PtrValue
)
v
.
PointTo
(
reflect
.
MakeZero
(
v
.
Type
()
.
(
*
reflect
.
PtrType
)
.
Elem
()))
if
err
:=
Unmarshal
([]
byte
(
in
),
v
.
Interface
());
err
!=
nil
{
t
.
Errorf
(
"#%d: %v"
,
i
,
err
)
continue
}
if
!
reflect
.
DeepEqual
(
v
.
Elem
()
.
Interface
(),
tt
.
out
)
{
t
.
Errorf
(
"#%d: mismatch
\n
have: %#+v
\n
want: %#+v"
,
i
,
v
.
Elem
()
.
Interface
(),
tt
.
out
)
data
,
_
:=
Marshal
(
v
.
Elem
()
.
Interface
())
println
(
string
(
data
))
data
,
_
=
Marshal
(
tt
.
out
)
println
(
string
(
data
))
return
continue
}
}
}
}
func
TestDecodeEmptyArray
(
t
*
testing
.
T
)
{
func
TestUnmarshalMarshal
(
t
*
testing
.
T
)
{
nb
:=
newDecoder
(
nil
,
nil
)
var
v
interface
{}
nb
.
Array
()
if
err
:=
Unmarshal
(
jsonBig
,
&
v
);
err
!=
nil
{
assertResult
(
t
,
nb
.
Data
(),
[]
interface
{}{})
t
.
Fatalf
(
"Unmarshal: %v"
,
err
)
}
b
,
err
:=
Marshal
(
v
)
if
err
!=
nil
{
t
.
Fatalf
(
"Marshal: %v"
,
err
)
}
if
bytes
.
Compare
(
jsonBig
,
b
)
!=
0
{
t
.
Errorf
(
"Marshal jsonBig"
)
diff
(
t
,
b
,
jsonBig
)
return
}
}
}
func
TestDecodeEmptyMap
(
t
*
testing
.
T
)
{
func
noSpace
(
c
int
)
int
{
nb
:=
newDecoder
(
nil
,
nil
)
if
isSpace
(
c
)
{
nb
.
Map
()
return
-
1
assertResult
(
t
,
nb
.
Data
(),
map
[
string
]
interface
{}{})
}
return
c
}
}
func
TestDecodeFlushElem
(
t
*
testing
.
T
)
{
type
All
struct
{
testVec
:=
new
(
vector
.
Vector
)
.
Resize
(
2
,
2
)
Bool
bool
nb
:=
newDecoder
(
testVec
,
1
)
Int
int
nb
.
Float64
(
3.14159
)
Int8
int8
nb
.
Flush
()
Int16
int16
assertResult
(
t
,
testVec
.
Data
(),
[]
interface
{}{
nil
,
float64
(
3.14159
)})
Int32
int32
}
Int64
int64
Uint
uint
Uint8
uint8
Uint16
uint16
Uint32
uint32
Uint64
uint64
Uintptr
uintptr
Float
float
Float32
float32
Float64
float64
func
TestDecodeFlushKey
(
t
*
testing
.
T
)
{
Foo
string
"bar"
testMap
:=
make
(
map
[
string
]
interface
{})
nb
:=
newDecoder
(
testMap
,
"key"
)
nb
.
Float64
(
3.14159
)
nb
.
Flush
()
assertResult
(
t
,
testMap
,
map
[
string
]
interface
{}{
"key"
:
float64
(
3.14159
)})
}
// Elem() and Key() are hard to test in isolation because all they do
PBool
*
bool
// is create a new, properly initialized, decoder, and modify state of
PInt
*
int
// the underlying decoder. I'm testing them through already tested
PInt8
*
int8
// Array(), String(), and Flush().
PInt16
*
int16
PInt32
*
int32
func
TestDecodeElem
(
t
*
testing
.
T
)
{
PInt64
*
int64
nb
:=
newDecoder
(
nil
,
nil
)
PUint
*
uint
nb
.
Array
()
PUint8
*
uint8
var
b
Builder
=
nb
.
Elem
(
0
)
PUint16
*
uint16
b
.
String
(
"0"
)
PUint32
*
uint32
b
.
Flush
()
PUint64
*
uint64
assertResult
(
t
,
nb
.
Data
(),
[]
interface
{}{
"0"
})
PUintptr
*
uintptr
}
PFloat
*
float
PFloat32
*
float32
PFloat64
*
float64
String
string
PString
*
string
func
TestDecodeKey
(
t
*
testing
.
T
)
{
Map
map
[
string
]
Small
nb
:=
newDecoder
(
nil
,
nil
)
MapP
map
[
string
]
*
Small
nb
.
Map
()
PMap
*
map
[
string
]
Small
var
b
Builder
=
nb
.
Key
(
"a"
)
PMapP
*
map
[
string
]
*
Small
b
.
String
(
"0"
)
b
.
Flush
()
EmptyMap
map
[
string
]
Small
assertResult
(
t
,
nb
.
Data
(),
map
[
string
]
interface
{}{
"a"
:
"0"
})
NilMap
map
[
string
]
Small
Slice
[]
Small
SliceP
[]
*
Small
PSlice
*
[]
Small
PSliceP
*
[]
*
Small
EmptySlice
[]
Small
NilSlice
[]
Small
StringSlice
[]
string
ByteSlice
[]
byte
Small
Small
PSmall
*
Small
PPSmall
**
Small
Interface
interface
{}
PInterface
*
interface
{}
}
}
func
assertResult
(
t
*
testing
.
T
,
results
,
expected
interface
{})
{
type
Small
struct
{
if
!
reflect
.
DeepEqual
(
results
,
expected
)
{
Tag
string
t
.
Fatalf
(
"have %T(%#v) want %T(%#v)"
,
results
,
results
,
expected
,
expected
)
}
}
}
type
decodeTest
struct
{
var
allValue
=
All
{
s
string
Bool
:
true
,
r
interface
{}
Int
:
2
,
Int8
:
3
,
Int16
:
4
,
Int32
:
5
,
Int64
:
6
,
Uint
:
7
,
Uint8
:
8
,
Uint16
:
9
,
Uint32
:
10
,
Uint64
:
11
,
Uintptr
:
12
,
Float
:
13.1
,
Float32
:
14.1
,
Float64
:
15.1
,
Foo
:
"foo"
,
String
:
"16"
,
Map
:
map
[
string
]
Small
{
"17"
:
Small
{
Tag
:
"tag17"
},
"18"
:
Small
{
Tag
:
"tag18"
},
},
MapP
:
map
[
string
]
*
Small
{
"19"
:
&
Small
{
Tag
:
"tag19"
},
"20"
:
nil
,
},
EmptyMap
:
map
[
string
]
Small
{},
Slice
:
[]
Small
{
Small
{
Tag
:
"tag20"
},
Small
{
Tag
:
"tag21"
}},
SliceP
:
[]
*
Small
{
&
Small
{
Tag
:
"tag22"
},
nil
,
&
Small
{
Tag
:
"tag23"
}},
EmptySlice
:
[]
Small
{},
StringSlice
:
[]
string
{
"str24"
,
"str25"
,
"str26"
},
ByteSlice
:
[]
byte
{
27
,
28
,
29
},
Small
:
Small
{
Tag
:
"tag30"
},
PSmall
:
&
Small
{
Tag
:
"tag31"
},
Interface
:
float64
(
5.2
),
}
}
var
tests
=
[]
decodeTest
{
var
pallValue
=
All
{
decodeTest
{
`null`
,
nil
},
PBool
:
&
allValue
.
Bool
,
decodeTest
{
`true`
,
true
},
PInt
:
&
allValue
.
Int
,
decodeTest
{
`false`
,
false
},
PInt8
:
&
allValue
.
Int8
,
decodeTest
{
`"abc"`
,
"abc"
},
PInt16
:
&
allValue
.
Int16
,
decodeTest
{
`123`
,
float64
(
123
)},
PInt32
:
&
allValue
.
Int32
,
decodeTest
{
`0.1`
,
float64
(
0.1
)},
PInt64
:
&
allValue
.
Int64
,
decodeTest
{
`1e-10`
,
float64
(
1e-10
)},
PUint
:
&
allValue
.
Uint
,
decodeTest
{
`[]`
,
[]
interface
{}{}},
PUint8
:
&
allValue
.
Uint8
,
decodeTest
{
`[1,2,3,4]`
,
[]
interface
{}{
float64
(
1
),
float64
(
2
),
float64
(
3
),
float64
(
4
)}},
PUint16
:
&
allValue
.
Uint16
,
decodeTest
{
`[1,2,"abc",null,true,false]`
,
[]
interface
{}{
float64
(
1
),
float64
(
2
),
"abc"
,
nil
,
true
,
false
}},
PUint32
:
&
allValue
.
Uint32
,
decodeTest
{
`{}`
,
map
[
string
]
interface
{}{}},
PUint64
:
&
allValue
.
Uint64
,
decodeTest
{
`{"a":1}`
,
map
[
string
]
interface
{}{
"a"
:
float64
(
1
)}},
PUintptr
:
&
allValue
.
Uintptr
,
decodeTest
{
`"q\u0302"`
,
"q
\u0302
"
},
PFloat
:
&
allValue
.
Float
,
PFloat32
:
&
allValue
.
Float32
,
PFloat64
:
&
allValue
.
Float64
,
PString
:
&
allValue
.
String
,
PMap
:
&
allValue
.
Map
,
PMapP
:
&
allValue
.
MapP
,
PSlice
:
&
allValue
.
Slice
,
PSliceP
:
&
allValue
.
SliceP
,
PPSmall
:
&
allValue
.
PSmall
,
PInterface
:
&
allValue
.
Interface
,
}
}
func
TestDecode
(
t
*
testing
.
T
)
{
var
allValueIndent
=
`{
for
_
,
test
:=
range
tests
{
"bool": true,
if
val
,
err
:=
Decode
(
test
.
s
);
err
!=
nil
||
!
reflect
.
DeepEqual
(
val
,
test
.
r
)
{
"int": 2,
t
.
Errorf
(
"Decode(%#q) = %v, %v want %v, nil"
,
test
.
s
,
val
,
err
,
test
.
r
)
"int8": 3,
"int16": 4,
"int32": 5,
"int64": 6,
"uint": 7,
"uint8": 8,
"uint16": 9,
"uint32": 10,
"uint64": 11,
"uintptr": 12,
"float": 13.1,
"float32": 14.1,
"float64": 15.1,
"bar": "foo",
"pbool": null,
"pint": null,
"pint8": null,
"pint16": null,
"pint32": null,
"pint64": null,
"puint": null,
"puint8": null,
"puint16": null,
"puint32": null,
"puint64": null,
"puintptr": null,
"pfloat": null,
"pfloat32": null,
"pfloat64": null,
"string": "16",
"pstring": null,
"map": {
"17": {
"tag": "tag17"
},
"18": {
"tag": "tag18"
}
}
}
},
}
"mapp": {
"19": {
"tag": "tag19"
},
"20": null
},
"pmap": null,
"pmapp": null,
"emptymap": {},
"nilmap": null,
"slice": [
{
"tag": "tag20"
},
{
"tag": "tag21"
}
],
"slicep": [
{
"tag": "tag22"
},
null,
{
"tag": "tag23"
}
],
"pslice": null,
"pslicep": null,
"emptyslice": [],
"nilslice": [],
"stringslice": [
"str24",
"str25",
"str26"
],
"byteslice": [
27,
28,
29
],
"small": {
"tag": "tag30"
},
"psmall": {
"tag": "tag31"
},
"ppsmall": null,
"interface": 5.2,
"pinterface": null
}`
var
allValueCompact
=
strings
.
Map
(
noSpace
,
allValueIndent
)
var
pallValueIndent
=
`{
"bool": false,
"int": 0,
"int8": 0,
"int16": 0,
"int32": 0,
"int64": 0,
"uint": 0,
"uint8": 0,
"uint16": 0,
"uint32": 0,
"uint64": 0,
"uintptr": 0,
"float": 0,
"float32": 0,
"float64": 0,
"bar": "",
"pbool": true,
"pint": 2,
"pint8": 3,
"pint16": 4,
"pint32": 5,
"pint64": 6,
"puint": 7,
"puint8": 8,
"puint16": 9,
"puint32": 10,
"puint64": 11,
"puintptr": 12,
"pfloat": 13.1,
"pfloat32": 14.1,
"pfloat64": 15.1,
"string": "",
"pstring": "16",
"map": null,
"mapp": null,
"pmap": {
"17": {
"tag": "tag17"
},
"18": {
"tag": "tag18"
}
},
"pmapp": {
"19": {
"tag": "tag19"
},
"20": null
},
"emptymap": null,
"nilmap": null,
"slice": [],
"slicep": [],
"pslice": [
{
"tag": "tag20"
},
{
"tag": "tag21"
}
],
"pslicep": [
{
"tag": "tag22"
},
null,
{
"tag": "tag23"
}
],
"emptyslice": [],
"nilslice": [],
"stringslice": [],
"byteslice": [],
"small": {
"tag": ""
},
"psmall": null,
"ppsmall": {
"tag": "tag31"
},
"interface": null,
"pinterface": 5.2
}`
var
pallValueCompact
=
strings
.
Map
(
noSpace
,
pallValueIndent
)
src/pkg/json/encode.go
0 → 100644
View file @
dba9d62b
// Copyright 2010 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
(
"os"
"bytes"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
)
// Marshal returns the JSON encoding of v.
//
// Marshal traverses the value v recursively.
// If an encountered value implements the Marshaler interface,
// Marshal calls its MarshalJSON method to produce JSON.
//
// Otherwise, Marshal uses the following type-dependent default encodings:
//
// Boolean values encode as JSON booleans.
//
// Floating point and integer values encode as JSON numbers.
//
// String values encode as JSON strings, with each invalid UTF-8 sequence
// replaced by the encoding of the Unicode replacement character U+FFFD.
//
// Array and slice values encode as JSON arrays.
//
// Struct values encode as JSON objects. Each struct field becomes
// a member of the object. By default the object's key name is the
// struct field name converted to lower case. If the struct field
// has a tag, that tag will be used as the name instead.
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
// as map keys.
//
// Pointer values encode as the value pointed at.
// A nil pointer encodes as the null JSON object.
//
// Interface values encode as the value contained in the interface.
// A nil interface value encodes as the null JSON object.
//
// Channel, complex, and function values cannot be encoded in JSON.
// Attempting to encode such a value causes Marshal to return
// an InvalidTypeError.
//
// JSON cannot represent cyclic data structures and Marshal does not
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func
Marshal
(
v
interface
{})
([]
byte
,
os
.
Error
)
{
e
:=
&
encodeState
{}
err
:=
e
.
marshal
(
v
)
if
err
!=
nil
{
return
nil
,
err
}
return
e
.
Bytes
(),
nil
}
// MarshalIndent is like Marshal but applies Indent to format the output.
func
MarshalIndent
(
v
interface
{},
prefix
,
indent
string
)
([]
byte
,
os
.
Error
)
{
b
,
err
:=
Marshal
(
v
)
if
err
!=
nil
{
return
nil
,
err
}
var
buf
bytes
.
Buffer
err
=
Indent
(
&
buf
,
b
,
prefix
,
indent
)
if
err
!=
nil
{
return
nil
,
err
}
return
buf
.
Bytes
(),
nil
}
// Marshaler is the interface implemented by objects that
// can marshal themselves into valid JSON.
type
Marshaler
interface
{
MarshalJSON
()
([]
byte
,
os
.
Error
)
}
type
UnsupportedTypeError
struct
{
Type
reflect
.
Type
}
func
(
e
*
UnsupportedTypeError
)
String
()
string
{
return
"json: unsupported type: "
+
e
.
Type
.
String
()
}
type
MarshalerError
struct
{
Type
reflect
.
Type
Error
os
.
Error
}
func
(
e
*
MarshalerError
)
String
()
string
{
return
"json: error calling MarshalJSON for type "
+
e
.
Type
.
String
()
+
": "
+
e
.
Error
.
String
()
}
type
interfaceOrPtrValue
interface
{
IsNil
()
bool
Elem
()
reflect
.
Value
}
var
hex
=
"0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
type
encodeState
struct
{
bytes
.
Buffer
// accumulated output
}
func
(
e
*
encodeState
)
marshal
(
v
interface
{})
(
err
os
.
Error
)
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
if
_
,
ok
:=
r
.
(
runtime
.
Error
);
ok
{
panic
(
r
)
}
err
=
r
.
(
os
.
Error
)
}
}()
e
.
reflectValue
(
reflect
.
NewValue
(
v
))
return
nil
}
func
(
e
*
encodeState
)
error
(
err
os
.
Error
)
{
panic
(
err
)
}
func
(
e
*
encodeState
)
reflectValue
(
v
reflect
.
Value
)
{
if
v
==
nil
{
e
.
WriteString
(
"null"
)
return
}
if
j
,
ok
:=
v
.
Interface
()
.
(
Marshaler
);
ok
{
b
,
err
:=
j
.
MarshalJSON
()
if
err
==
nil
{
// copy JSON into buffer, checking validity.
err
=
Compact
(
&
e
.
Buffer
,
b
)
}
if
err
!=
nil
{
e
.
error
(
&
MarshalerError
{
v
.
Type
(),
err
})
}
return
}
switch
v
:=
v
.
(
type
)
{
case
*
reflect
.
BoolValue
:
x
:=
v
.
Get
()
if
x
{
e
.
WriteString
(
"true"
)
}
else
{
e
.
WriteString
(
"false"
)
}
case
*
reflect
.
IntValue
:
e
.
WriteString
(
strconv
.
Itoa
(
v
.
Get
()))
case
*
reflect
.
Int8Value
:
e
.
WriteString
(
strconv
.
Itoa
(
int
(
v
.
Get
())))
case
*
reflect
.
Int16Value
:
e
.
WriteString
(
strconv
.
Itoa
(
int
(
v
.
Get
())))
case
*
reflect
.
Int32Value
:
e
.
WriteString
(
strconv
.
Itoa
(
int
(
v
.
Get
())))
case
*
reflect
.
Int64Value
:
e
.
WriteString
(
strconv
.
Itoa64
(
v
.
Get
()))
case
*
reflect
.
UintValue
:
e
.
WriteString
(
strconv
.
Uitoa
(
v
.
Get
()))
case
*
reflect
.
Uint8Value
:
e
.
WriteString
(
strconv
.
Uitoa
(
uint
(
v
.
Get
())))
case
*
reflect
.
Uint16Value
:
e
.
WriteString
(
strconv
.
Uitoa
(
uint
(
v
.
Get
())))
case
*
reflect
.
Uint32Value
:
e
.
WriteString
(
strconv
.
Uitoa
(
uint
(
v
.
Get
())))
case
*
reflect
.
Uint64Value
:
e
.
WriteString
(
strconv
.
Uitoa64
(
v
.
Get
()))
case
*
reflect
.
UintptrValue
:
e
.
WriteString
(
strconv
.
Uitoa64
(
uint64
(
v
.
Get
())))
case
*
reflect
.
FloatValue
:
e
.
WriteString
(
strconv
.
Ftoa
(
v
.
Get
(),
'g'
,
-
1
))
case
*
reflect
.
Float32Value
:
e
.
WriteString
(
strconv
.
Ftoa32
(
v
.
Get
(),
'g'
,
-
1
))
case
*
reflect
.
Float64Value
:
e
.
WriteString
(
strconv
.
Ftoa64
(
v
.
Get
(),
'g'
,
-
1
))
case
*
reflect
.
StringValue
:
e
.
string
(
v
.
Get
())
case
*
reflect
.
StructValue
:
e
.
WriteByte
(
'{'
)
t
:=
v
.
Type
()
.
(
*
reflect
.
StructType
)
n
:=
v
.
NumField
()
for
i
:=
0
;
i
<
n
;
i
++
{
if
i
>
0
{
e
.
WriteByte
(
','
)
}
f
:=
t
.
Field
(
i
)
if
f
.
Tag
!=
""
{
e
.
string
(
f
.
Tag
)
}
else
{
e
.
string
(
strings
.
ToLower
(
f
.
Name
))
}
e
.
WriteByte
(
':'
)
e
.
reflectValue
(
v
.
Field
(
i
))
}
e
.
WriteByte
(
'}'
)
case
*
reflect
.
MapValue
:
if
_
,
ok
:=
v
.
Type
()
.
(
*
reflect
.
MapType
)
.
Key
()
.
(
*
reflect
.
StringType
);
!
ok
{
e
.
error
(
&
UnsupportedTypeError
{
v
.
Type
()})
}
if
v
.
IsNil
()
{
e
.
WriteString
(
"null"
)
break
}
e
.
WriteByte
(
'{'
)
var
sv
stringValues
=
v
.
Keys
()
sort
.
Sort
(
sv
)
for
i
,
k
:=
range
sv
{
if
i
>
0
{
e
.
WriteByte
(
','
)
}
e
.
string
(
k
.
(
*
reflect
.
StringValue
)
.
Get
())
e
.
WriteByte
(
':'
)
e
.
reflectValue
(
v
.
Elem
(
k
))
}
e
.
WriteByte
(
'}'
)
case
reflect
.
ArrayOrSliceValue
:
e
.
WriteByte
(
'['
)
n
:=
v
.
Len
()
for
i
:=
0
;
i
<
n
;
i
++
{
if
i
>
0
{
e
.
WriteByte
(
','
)
}
e
.
reflectValue
(
v
.
Elem
(
i
))
}
e
.
WriteByte
(
']'
)
case
interfaceOrPtrValue
:
if
v
.
IsNil
()
{
e
.
WriteString
(
"null"
)
return
}
e
.
reflectValue
(
v
.
Elem
())
default
:
e
.
error
(
&
UnsupportedTypeError
{
v
.
Type
()})
}
return
}
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type
stringValues
[]
reflect
.
Value
func
(
sv
stringValues
)
Len
()
int
{
return
len
(
sv
)
}
func
(
sv
stringValues
)
Swap
(
i
,
j
int
)
{
sv
[
i
],
sv
[
j
]
=
sv
[
j
],
sv
[
i
]
}
func
(
sv
stringValues
)
Less
(
i
,
j
int
)
bool
{
return
sv
.
get
(
i
)
<
sv
.
get
(
j
)
}
func
(
sv
stringValues
)
get
(
i
int
)
string
{
return
sv
[
i
]
.
(
*
reflect
.
StringValue
)
.
Get
()
}
func
(
e
*
encodeState
)
string
(
s
string
)
{
e
.
WriteByte
(
'"'
)
for
_
,
c
:=
range
s
{
switch
{
case
c
<
0x20
:
e
.
WriteString
(
`\u00`
)
e
.
WriteByte
(
hex
[
c
>>
4
])
e
.
WriteByte
(
hex
[
c
&
0xF
])
case
c
==
'\\'
||
c
==
'"'
:
e
.
WriteByte
(
'\\'
)
fallthrough
default
:
e
.
WriteRune
(
c
)
}
}
e
.
WriteByte
(
'"'
)
}
src/pkg/json/scanner.go
View file @
dba9d62b
...
@@ -181,6 +181,10 @@ func (s *scanner) popParseState() {
...
@@ -181,6 +181,10 @@ func (s *scanner) popParseState() {
}
}
}
}
func
isSpace
(
c
int
)
bool
{
return
c
==
' '
||
c
==
'\t'
||
c
==
'\r'
||
c
==
'\n'
}
// NOTE(rsc): The various instances of
// NOTE(rsc): The various instances of
//
//
// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
// if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
...
@@ -590,7 +594,7 @@ func stateError(s *scanner, c int) int {
...
@@ -590,7 +594,7 @@ func stateError(s *scanner, c int) int {
// error records an error and switches to the error state.
// error records an error and switches to the error state.
func
(
s
*
scanner
)
error
(
c
int
,
context
string
)
int
{
func
(
s
*
scanner
)
error
(
c
int
,
context
string
)
int
{
s
.
step
=
stateError
s
.
step
=
stateError
s
.
err
=
SyntaxError
(
"invalid character
'"
+
quoteChar
(
c
)
+
"'
"
+
context
)
s
.
err
=
SyntaxError
(
"invalid character
"
+
quoteChar
(
c
)
+
"
"
+
context
)
return
scanError
return
scanError
}
}
...
...
src/pkg/json/scanner_test.go
View file @
dba9d62b
...
@@ -175,6 +175,7 @@ func diff(t *testing.T, a, b []byte) {
...
@@ -175,6 +175,7 @@ func diff(t *testing.T, a, b []byte) {
j
=
0
j
=
0
}
}
t
.
Errorf
(
"diverge at %d: «%s» vs «%s»"
,
i
,
trim
(
a
[
j
:
]),
trim
(
b
[
j
:
]))
t
.
Errorf
(
"diverge at %d: «%s» vs «%s»"
,
i
,
trim
(
a
[
j
:
]),
trim
(
b
[
j
:
]))
return
}
}
}
}
}
}
...
@@ -191,9 +192,11 @@ func trim(b []byte) []byte {
...
@@ -191,9 +192,11 @@ func trim(b []byte) []byte {
var
jsonBig
[]
byte
var
jsonBig
[]
byte
func
init
()
{
func
init
()
{
var
buf
bytes
.
Buffer
b
,
err
:=
Marshal
(
genValue
(
10000
))
Marshal
(
&
buf
,
genValue
(
100000
))
if
err
!=
nil
{
jsonBig
=
buf
.
Bytes
()
panic
(
err
)
}
jsonBig
=
b
}
}
func
genValue
(
n
int
)
interface
{}
{
func
genValue
(
n
int
)
interface
{}
{
...
...
src/pkg/json/struct.go
deleted
100644 → 0
View file @
214a55b0
// Copyright 2009 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.
// Marshalling and unmarshalling of
// JSON data into Go structs using reflection.
package
json
import
(
"bytes"
"fmt"
"io"
"os"
"reflect"
"strings"
)
type
structBuilder
struct
{
val
reflect
.
Value
// if map_ != nil, write val to map_[key] on each change
map_
*
reflect
.
MapValue
key
reflect
.
Value
}
var
nobuilder
*
structBuilder
func
isfloat
(
v
reflect
.
Value
)
bool
{
switch
v
.
(
type
)
{
case
*
reflect
.
FloatValue
,
*
reflect
.
Float32Value
,
*
reflect
.
Float64Value
:
return
true
}
return
false
}
func
setfloat
(
v
reflect
.
Value
,
f
float64
)
{
switch
v
:=
v
.
(
type
)
{
case
*
reflect
.
FloatValue
:
v
.
Set
(
float
(
f
))
case
*
reflect
.
Float32Value
:
v
.
Set
(
float32
(
f
))
case
*
reflect
.
Float64Value
:
v
.
Set
(
float64
(
f
))
}
}
func
setint
(
v
reflect
.
Value
,
i
int64
)
{
switch
v
:=
v
.
(
type
)
{
case
*
reflect
.
IntValue
:
v
.
Set
(
int
(
i
))
case
*
reflect
.
Int8Value
:
v
.
Set
(
int8
(
i
))
case
*
reflect
.
Int16Value
:
v
.
Set
(
int16
(
i
))
case
*
reflect
.
Int32Value
:
v
.
Set
(
int32
(
i
))
case
*
reflect
.
Int64Value
:
v
.
Set
(
int64
(
i
))
case
*
reflect
.
UintValue
:
v
.
Set
(
uint
(
i
))
case
*
reflect
.
Uint8Value
:
v
.
Set
(
uint8
(
i
))
case
*
reflect
.
Uint16Value
:
v
.
Set
(
uint16
(
i
))
case
*
reflect
.
Uint32Value
:
v
.
Set
(
uint32
(
i
))
case
*
reflect
.
Uint64Value
:
v
.
Set
(
uint64
(
i
))
}
}
// If updating b.val is not enough to update the original,
// copy a changed b.val out to the original.
func
(
b
*
structBuilder
)
Flush
()
{
if
b
==
nil
{
return
}
if
b
.
map_
!=
nil
{
b
.
map_
.
SetElem
(
b
.
key
,
b
.
val
)
}
}
func
(
b
*
structBuilder
)
Int64
(
i
int64
)
{
if
b
==
nil
{
return
}
v
:=
b
.
val
if
isfloat
(
v
)
{
setfloat
(
v
,
float64
(
i
))
}
else
{
setint
(
v
,
i
)
}
}
func
(
b
*
structBuilder
)
Uint64
(
i
uint64
)
{
if
b
==
nil
{
return
}
v
:=
b
.
val
if
isfloat
(
v
)
{
setfloat
(
v
,
float64
(
i
))
}
else
{
setint
(
v
,
int64
(
i
))
}
}
func
(
b
*
structBuilder
)
Float64
(
f
float64
)
{
if
b
==
nil
{
return
}
v
:=
b
.
val
if
isfloat
(
v
)
{
setfloat
(
v
,
f
)
}
else
{
setint
(
v
,
int64
(
f
))
}
}
func
(
b
*
structBuilder
)
Null
()
{}
func
(
b
*
structBuilder
)
String
(
s
string
)
{
if
b
==
nil
{
return
}
if
v
,
ok
:=
b
.
val
.
(
*
reflect
.
StringValue
);
ok
{
v
.
Set
(
s
)
}
}
func
(
b
*
structBuilder
)
Bool
(
tf
bool
)
{
if
b
==
nil
{
return
}
if
v
,
ok
:=
b
.
val
.
(
*
reflect
.
BoolValue
);
ok
{
v
.
Set
(
tf
)
}
}
func
(
b
*
structBuilder
)
Array
()
{
if
b
==
nil
{
return
}
if
v
,
ok
:=
b
.
val
.
(
*
reflect
.
SliceValue
);
ok
{
if
v
.
IsNil
()
{
v
.
Set
(
reflect
.
MakeSlice
(
v
.
Type
()
.
(
*
reflect
.
SliceType
),
0
,
8
))
}
}
}
func
(
b
*
structBuilder
)
Elem
(
i
int
)
Builder
{
if
b
==
nil
||
i
<
0
{
return
nobuilder
}
switch
v
:=
b
.
val
.
(
type
)
{
case
*
reflect
.
ArrayValue
:
if
i
<
v
.
Len
()
{
return
&
structBuilder
{
val
:
v
.
Elem
(
i
)}
}
case
*
reflect
.
SliceValue
:
if
i
>=
v
.
Cap
()
{
n
:=
v
.
Cap
()
if
n
<
8
{
n
=
8
}
for
n
<=
i
{
n
*=
2
}
nv
:=
reflect
.
MakeSlice
(
v
.
Type
()
.
(
*
reflect
.
SliceType
),
v
.
Len
(),
n
)
reflect
.
ArrayCopy
(
nv
,
v
)
v
.
Set
(
nv
)
}
if
v
.
Len
()
<=
i
&&
i
<
v
.
Cap
()
{
v
.
SetLen
(
i
+
1
)
}
if
i
<
v
.
Len
()
{
return
&
structBuilder
{
val
:
v
.
Elem
(
i
)}
}
}
return
nobuilder
}
func
(
b
*
structBuilder
)
Map
()
{
if
b
==
nil
{
return
}
if
v
,
ok
:=
b
.
val
.
(
*
reflect
.
PtrValue
);
ok
&&
v
.
IsNil
()
{
if
v
.
IsNil
()
{
v
.
PointTo
(
reflect
.
MakeZero
(
v
.
Type
()
.
(
*
reflect
.
PtrType
)
.
Elem
()))
b
.
Flush
()
}
b
.
map_
=
nil
b
.
val
=
v
.
Elem
()
}
if
v
,
ok
:=
b
.
val
.
(
*
reflect
.
MapValue
);
ok
&&
v
.
IsNil
()
{
v
.
Set
(
reflect
.
MakeMap
(
v
.
Type
()
.
(
*
reflect
.
MapType
)))
}
}
func
(
b
*
structBuilder
)
Key
(
k
string
)
Builder
{
if
b
==
nil
{
return
nobuilder
}
switch
v
:=
reflect
.
Indirect
(
b
.
val
)
.
(
type
)
{
case
*
reflect
.
StructValue
:
t
:=
v
.
Type
()
.
(
*
reflect
.
StructType
)
// Case-insensitive field lookup.
k
=
strings
.
ToLower
(
k
)
for
i
:=
0
;
i
<
t
.
NumField
();
i
++
{
if
strings
.
ToLower
(
t
.
Field
(
i
)
.
Name
)
==
k
{
return
&
structBuilder
{
val
:
v
.
Field
(
i
)}
}
}
case
*
reflect
.
MapValue
:
t
:=
v
.
Type
()
.
(
*
reflect
.
MapType
)
if
t
.
Key
()
!=
reflect
.
Typeof
(
k
)
{
break
}
key
:=
reflect
.
NewValue
(
k
)
elem
:=
v
.
Elem
(
key
)
if
elem
==
nil
{
v
.
SetElem
(
key
,
reflect
.
MakeZero
(
t
.
Elem
()))
elem
=
v
.
Elem
(
key
)
}
return
&
structBuilder
{
val
:
elem
,
map_
:
v
,
key
:
key
}
}
return
nobuilder
}
// Unmarshal parses the JSON syntax string s and fills in
// an arbitrary struct or slice pointed at by val.
// It uses the reflect package to assign to fields
// and arrays embedded in val. Well-formed data that does not fit
// into the struct is discarded.
//
// For example, given these definitions:
//
// type Email struct {
// Where string
// Addr string
// }
//
// type Result struct {
// Name string
// Phone string
// Email []Email
// }
//
// var r = Result{ "name", "phone", nil }
//
// unmarshalling the JSON syntax string
//
// {
// "email": [
// {
// "where": "home",
// "addr": "gre@example.com"
// },
// {
// "where": "work",
// "addr": "gre@work.com"
// }
// ],
// "name": "Grace R. Emlin",
// "address": "123 Main Street"
// }
//
// via Unmarshal(s, &r) is equivalent to assigning
//
// r = Result{
// "Grace R. Emlin", // name
// "phone", // no phone given
// []Email{
// Email{ "home", "gre@example.com" },
// Email{ "work", "gre@work.com" },
// },
// }
//
// Note that the field r.Phone has not been modified and
// that the JSON field "address" was discarded.
//
// Because Unmarshal uses the reflect package, it can only
// assign to upper case fields. Unmarshal uses a case-insensitive
// comparison to match JSON field names to struct field names.
//
// To unmarshal a top-level JSON array, pass in a pointer to an empty
// slice of the correct type.
//
// On success, Unmarshal returns with ok set to true.
// On a syntax error, it returns with ok set to false and errtok
// set to the offending token.
func
Unmarshal
(
s
string
,
val
interface
{})
(
ok
bool
,
errtok
string
)
{
v
:=
reflect
.
NewValue
(
val
)
var
b
*
structBuilder
// If val is a pointer to a slice, we append to the slice.
if
ptr
,
ok
:=
v
.
(
*
reflect
.
PtrValue
);
ok
{
if
slice
,
ok
:=
ptr
.
Elem
()
.
(
*
reflect
.
SliceValue
);
ok
{
b
=
&
structBuilder
{
val
:
slice
}
}
}
if
b
==
nil
{
b
=
&
structBuilder
{
val
:
v
}
}
ok
,
_
,
errtok
=
Parse
(
s
,
b
)
if
!
ok
{
return
false
,
errtok
}
return
true
,
""
}
type
MarshalError
struct
{
T
reflect
.
Type
}
func
(
e
*
MarshalError
)
String
()
string
{
return
"json cannot encode value of type "
+
e
.
T
.
String
()
}
type
writeState
struct
{
bytes
.
Buffer
indent
string
newlines
bool
depth
int
}
func
(
s
*
writeState
)
descend
(
bra
byte
)
{
s
.
depth
++
s
.
WriteByte
(
bra
)
}
func
(
s
*
writeState
)
ascend
(
ket
byte
)
{
s
.
depth
--
s
.
writeIndent
()
s
.
WriteByte
(
ket
)
}
func
(
s
*
writeState
)
writeIndent
()
{
if
s
.
newlines
{
s
.
WriteByte
(
'\n'
)
}
for
i
:=
0
;
i
<
s
.
depth
;
i
++
{
s
.
WriteString
(
s
.
indent
)
}
}
func
(
s
*
writeState
)
writeArrayOrSlice
(
val
reflect
.
ArrayOrSliceValue
)
{
s
.
descend
(
'['
)
for
i
:=
0
;
i
<
val
.
Len
();
i
++
{
s
.
writeIndent
()
s
.
writeValue
(
val
.
Elem
(
i
))
if
i
<
val
.
Len
()
-
1
{
s
.
WriteByte
(
','
)
}
}
s
.
ascend
(
']'
)
}
func
(
s
*
writeState
)
writeMap
(
val
*
reflect
.
MapValue
)
{
key
:=
val
.
Type
()
.
(
*
reflect
.
MapType
)
.
Key
()
if
_
,
ok
:=
key
.
(
*
reflect
.
StringType
);
!
ok
{
panic
(
&
MarshalError
{
val
.
Type
()})
}
s
.
descend
(
'{'
)
keys
:=
val
.
Keys
()
for
i
:=
0
;
i
<
len
(
keys
);
i
++
{
s
.
writeIndent
()
fmt
.
Fprintf
(
s
,
"%s:"
,
Quote
(
keys
[
i
]
.
(
*
reflect
.
StringValue
)
.
Get
()))
s
.
writeValue
(
val
.
Elem
(
keys
[
i
]))
if
i
<
len
(
keys
)
-
1
{
s
.
WriteByte
(
','
)
}
}
s
.
ascend
(
'}'
)
}
func
(
s
*
writeState
)
writeStruct
(
val
*
reflect
.
StructValue
)
{
s
.
descend
(
'{'
)
typ
:=
val
.
Type
()
.
(
*
reflect
.
StructType
)
for
i
:=
0
;
i
<
val
.
NumField
();
i
++
{
s
.
writeIndent
()
fmt
.
Fprintf
(
s
,
"%s:"
,
Quote
(
typ
.
Field
(
i
)
.
Name
))
s
.
writeValue
(
val
.
Field
(
i
))
if
i
<
val
.
NumField
()
-
1
{
s
.
WriteByte
(
','
)
}
}
s
.
ascend
(
'}'
)
}
func
(
s
*
writeState
)
writeValue
(
val
reflect
.
Value
)
{
if
val
==
nil
{
fmt
.
Fprint
(
s
,
"null"
)
return
}
switch
v
:=
val
.
(
type
)
{
case
*
reflect
.
StringValue
:
fmt
.
Fprint
(
s
,
Quote
(
v
.
Get
()))
case
*
reflect
.
ArrayValue
:
s
.
writeArrayOrSlice
(
v
)
case
*
reflect
.
SliceValue
:
s
.
writeArrayOrSlice
(
v
)
case
*
reflect
.
MapValue
:
s
.
writeMap
(
v
)
case
*
reflect
.
StructValue
:
s
.
writeStruct
(
v
)
case
*
reflect
.
ChanValue
,
*
reflect
.
UnsafePointerValue
,
*
reflect
.
FuncValue
:
panic
(
&
MarshalError
{
val
.
Type
()})
case
*
reflect
.
InterfaceValue
:
if
v
.
IsNil
()
{
fmt
.
Fprint
(
s
,
"null"
)
}
else
{
s
.
writeValue
(
v
.
Elem
())
}
case
*
reflect
.
PtrValue
:
if
v
.
IsNil
()
{
fmt
.
Fprint
(
s
,
"null"
)
}
else
{
s
.
writeValue
(
v
.
Elem
())
}
case
*
reflect
.
UintptrValue
:
fmt
.
Fprintf
(
s
,
"%d"
,
v
.
Get
())
case
*
reflect
.
Uint64Value
:
fmt
.
Fprintf
(
s
,
"%d"
,
v
.
Get
())
case
*
reflect
.
Uint32Value
:
fmt
.
Fprintf
(
s
,
"%d"
,
v
.
Get
())
case
*
reflect
.
Uint16Value
:
fmt
.
Fprintf
(
s
,
"%d"
,
v
.
Get
())
case
*
reflect
.
Uint8Value
:
fmt
.
Fprintf
(
s
,
"%d"
,
v
.
Get
())
default
:
value
:=
val
.
(
reflect
.
Value
)
fmt
.
Fprintf
(
s
,
"%#v"
,
value
.
Interface
())
}
}
func
(
s
*
writeState
)
marshal
(
w
io
.
Writer
,
val
interface
{})
(
err
os
.
Error
)
{
defer
func
()
{
if
e
:=
recover
();
e
!=
nil
{
err
=
e
.
(
*
MarshalError
)
}
}()
s
.
writeValue
(
reflect
.
NewValue
(
val
))
if
s
.
newlines
{
s
.
WriteByte
(
'\n'
)
}
_
,
err
=
s
.
WriteTo
(
w
)
return
}
// Marshal writes the JSON encoding of val to w.
//
// Due to limitations in JSON, val cannot include cyclic data
// structures, channels, functions, or maps.
func
Marshal
(
w
io
.
Writer
,
val
interface
{})
os
.
Error
{
s
:=
&
writeState
{
indent
:
""
,
newlines
:
false
,
depth
:
0
}
return
s
.
marshal
(
w
,
val
)
}
// MarshalIndent writes the JSON encoding of val to w,
// indenting nested values using the indent string.
//
// Due to limitations in JSON, val cannot include cyclic data
// structures, channels, functions, or maps.
func
MarshalIndent
(
w
io
.
Writer
,
val
interface
{},
indent
string
)
os
.
Error
{
s
:=
&
writeState
{
indent
:
indent
,
newlines
:
true
,
depth
:
0
}
return
s
.
marshal
(
w
,
val
)
}
src/pkg/json/struct_test.go
deleted
100644 → 0
View file @
214a55b0
// Copyright 2009 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
(
"bytes"
"reflect"
"strconv"
"testing"
)
type
myStruct
struct
{
T
bool
F
bool
S
string
I8
int8
I16
int16
I32
int32
I64
int64
U8
uint8
U16
uint16
U32
uint32
U64
uint64
I
int
U
uint
Fl
float
Fl32
float32
Fl64
float64
A
[]
string
My
*
myStruct
Map
map
[
string
][]
int
MapStruct
map
[
string
]
myStruct
MapPtrStruct
map
[
string
]
*
myStruct
}
const
encoded
=
`{"t":true,"f":false,"s":"abc","i8":1,"i16":2,"i32":3,"i64":4,`
+
` "u8":5,"u16":6,"u32":7,"u64":8,`
+
` "i":-9,"u":10,"bogusfield":"should be ignored",`
+
` "fl":11.5,"fl32":12.25,"fl64":13.75,`
+
` "a":["x","y","z"],"my":{"s":"subguy"},`
+
`"map":{"k1":[1,2,3],"k2":[],"k3":[3,4]},`
+
`"mapstruct":{"m1":{"u8":8}},`
+
`"mapptrstruct":{"m1":{"u8":8}}}`
var
decodedMap
=
map
[
string
][]
int
{
"k1"
:
[]
int
{
1
,
2
,
3
},
"k2"
:
[]
int
{},
"k3"
:
[]
int
{
3
,
4
},
}
var
decodedMapStruct
=
map
[
string
]
myStruct
{
"m1"
:
myStruct
{
U8
:
8
},
}
var
decodedMapPtrStruct
=
map
[
string
]
*
myStruct
{
"m1"
:
&
myStruct
{
U8
:
8
},
}
func
check
(
t
*
testing
.
T
,
ok
bool
,
name
string
,
v
interface
{})
{
if
!
ok
{
t
.
Errorf
(
"%s = %v (BAD)"
,
name
,
v
)
}
else
{
t
.
Logf
(
"%s = %v (good)"
,
name
,
v
)
}
}
const
whiteSpaceEncoded
=
"
\t
{
\n\"
s
\"\r
:
\"
string
\"\v
}"
func
TestUnmarshalWhitespace
(
t
*
testing
.
T
)
{
var
m
myStruct
ok
,
errtok
:=
Unmarshal
(
whiteSpaceEncoded
,
&
m
)
if
!
ok
{
t
.
Fatalf
(
"Unmarshal failed near %s"
,
errtok
)
}
check
(
t
,
m
.
S
==
"string"
,
"string"
,
m
.
S
)
}
func
TestUnmarshal
(
t
*
testing
.
T
)
{
var
m
myStruct
m
.
F
=
true
ok
,
errtok
:=
Unmarshal
(
encoded
,
&
m
)
if
!
ok
{
t
.
Fatalf
(
"Unmarshal failed near %s"
,
errtok
)
}
check
(
t
,
m
.
T
==
true
,
"t"
,
m
.
T
)
check
(
t
,
m
.
F
==
false
,
"f"
,
m
.
F
)
check
(
t
,
m
.
S
==
"abc"
,
"s"
,
m
.
S
)
check
(
t
,
m
.
I8
==
1
,
"i8"
,
m
.
I8
)
check
(
t
,
m
.
I16
==
2
,
"i16"
,
m
.
I16
)
check
(
t
,
m
.
I32
==
3
,
"i32"
,
m
.
I32
)
check
(
t
,
m
.
I64
==
4
,
"i64"
,
m
.
I64
)
check
(
t
,
m
.
U8
==
5
,
"u8"
,
m
.
U8
)
check
(
t
,
m
.
U16
==
6
,
"u16"
,
m
.
U16
)
check
(
t
,
m
.
U32
==
7
,
"u32"
,
m
.
U32
)
check
(
t
,
m
.
U64
==
8
,
"u64"
,
m
.
U64
)
check
(
t
,
m
.
I
==
-
9
,
"i"
,
m
.
I
)
check
(
t
,
m
.
U
==
10
,
"u"
,
m
.
U
)
check
(
t
,
m
.
Fl
==
11.5
,
"fl"
,
m
.
Fl
)
check
(
t
,
m
.
Fl32
==
12.25
,
"fl32"
,
m
.
Fl32
)
check
(
t
,
m
.
Fl64
==
13.75
,
"fl64"
,
m
.
Fl64
)
check
(
t
,
m
.
A
!=
nil
,
"a"
,
m
.
A
)
if
m
.
A
!=
nil
{
check
(
t
,
m
.
A
[
0
]
==
"x"
,
"a[0]"
,
m
.
A
[
0
])
check
(
t
,
m
.
A
[
1
]
==
"y"
,
"a[1]"
,
m
.
A
[
1
])
check
(
t
,
m
.
A
[
2
]
==
"z"
,
"a[2]"
,
m
.
A
[
2
])
}
check
(
t
,
m
.
My
!=
nil
,
"my"
,
m
.
My
)
if
m
.
My
!=
nil
{
check
(
t
,
m
.
My
.
S
==
"subguy"
,
"my.s"
,
m
.
My
.
S
)
}
check
(
t
,
reflect
.
DeepEqual
(
m
.
Map
,
decodedMap
),
"map"
,
m
.
Map
)
check
(
t
,
reflect
.
DeepEqual
(
m
.
MapStruct
,
decodedMapStruct
),
"mapstruct"
,
m
.
MapStruct
)
check
(
t
,
reflect
.
DeepEqual
(
m
.
MapPtrStruct
,
decodedMapPtrStruct
),
"mapptrstruct"
,
m
.
MapPtrStruct
)
}
type
Issue147Text
struct
{
Text
string
}
type
Issue147
struct
{
Test
[]
Issue147Text
}
const
issue147Input
=
`{"test": [{"text":"0"},{"text":"1"},{"text":"2"},
{"text":"3"},{"text":"4"},{"text":"5"},
{"text":"6"},{"text":"7"},{"text":"8"},
{"text":"9"},{"text":"10"},{"text":"11"},
{"text":"12"},{"text":"13"},{"text":"14"},
{"text":"15"},{"text":"16"},{"text":"17"},
{"text":"18"},{"text":"19"},{"text":"20"},
{"text":"21"},{"text":"22"},{"text":"23"},
{"text":"24"},{"text":"25"},{"text":"26"},
{"text":"27"},{"text":"28"},{"text":"29"}]}`
func
TestIssue147
(
t
*
testing
.
T
)
{
var
timeline
Issue147
Unmarshal
(
issue147Input
,
&
timeline
)
if
len
(
timeline
.
Test
)
!=
30
{
t
.
Errorf
(
"wrong length: got %d want 30"
,
len
(
timeline
.
Test
))
}
for
i
,
e
:=
range
timeline
.
Test
{
if
e
.
Text
!=
strconv
.
Itoa
(
i
)
{
t
.
Errorf
(
"index: %d got: %s want: %d"
,
i
,
e
.
Text
,
i
)
}
}
}
type
Issue114
struct
{
Text
string
}
const
issue114Input
=
`[{"text" : "0"}, {"text" : "1"}, {"text" : "2"}, {"text" : "3"}]`
func
TestIssue114
(
t
*
testing
.
T
)
{
var
items
[]
Issue114
Unmarshal
(
issue114Input
,
&
items
)
if
len
(
items
)
!=
4
{
t
.
Errorf
(
"wrong length: got %d want 4"
,
len
(
items
))
}
for
i
,
e
:=
range
items
{
if
e
.
Text
!=
strconv
.
Itoa
(
i
)
{
t
.
Errorf
(
"index: %d got: %s want: %d"
,
i
,
e
.
Text
,
i
)
}
}
}
type
marshalTest
struct
{
val
interface
{}
out
string
}
type
MTE
string
type
OneField
struct
{
a
int
}
type
ScalarWithString
int
const
(
AA
ScalarWithString
=
iota
BB
CC
)
var
scalarStrings
=
[]
string
{
"AA"
,
"BB"
,
"CC"
}
func
(
x
ScalarWithString
)
String
()
string
{
return
scalarStrings
[
x
]
}
var
marshalTests
=
[]
marshalTest
{
// basic string
marshalTest
{
nil
,
"null"
},
marshalTest
{
true
,
"true"
},
marshalTest
{
false
,
"false"
},
marshalTest
{
123
,
"123"
},
marshalTest
{
0.1
,
"0.1"
},
marshalTest
{
1e-10
,
"1e-10"
},
marshalTest
{
"teststring"
,
`"teststring"`
},
marshalTest
{[
4
]
int
{
1
,
2
,
3
,
4
},
"[1,2,3,4]"
},
marshalTest
{[]
int
{
1
,
2
,
3
,
4
},
"[1,2,3,4]"
},
marshalTest
{[]
interface
{}{
nil
},
"[null]"
},
marshalTest
{[][]
int
{[]
int
{
1
,
2
},
[]
int
{
3
,
4
}},
"[[1,2],[3,4]]"
},
marshalTest
{
map
[
string
]
string
{
"one"
:
"one"
},
`{"one":"one"}`
},
marshalTest
{
map
[
string
]
int
{
"one"
:
1
},
`{"one":1}`
},
marshalTest
{
map
[
string
]
interface
{}{
"null"
:
nil
},
`{"null":null}`
},
marshalTest
{
struct
{}{},
"{}"
},
marshalTest
{
struct
{
a
int
}{
1
},
`{"a":1}`
},
marshalTest
{
struct
{
a
interface
{}
}{
nil
},
`{"a":null}`
},
marshalTest
{
struct
{
a
int
b
string
}{
1
,
"hello"
},
`{"a":1,"b":"hello"}`
,
},
marshalTest
{
map
[
string
][]
int
{
"3"
:
[]
int
{
1
,
2
,
3
}},
`{"3":[1,2,3]}`
},
marshalTest
{
map
[
string
]
*
MTE
{
"hi"
:
nil
},
`{"hi":null}`
},
marshalTest
{
map
[
string
]
interface
{}{
"hi"
:
3
},
`{"hi":3}`
},
marshalTest
{
&
OneField
{
3
},
`{"a":3}`
},
marshalTest
{
"
\x05\x06
"
,
`"\u0005\u0006"`
},
marshalTest
{
uintptr
(
50000
),
"50000"
},
marshalTest
{
uint64
(
50000
),
"50000"
},
marshalTest
{
uint32
(
50000
),
"50000"
},
marshalTest
{
uint16
(
50000
),
"50000"
},
marshalTest
{
uint8
(
50
),
"50"
},
marshalTest
{
int64
(
50000
),
"50000"
},
marshalTest
{
int32
(
50000
),
"50000"
},
marshalTest
{
int16
(
10000
),
"10000"
},
marshalTest
{
int8
(
50
),
"50"
},
marshalTest
{
BB
,
"1"
},
}
func
TestMarshal
(
t
*
testing
.
T
)
{
for
_
,
tt
:=
range
marshalTests
{
var
buf
bytes
.
Buffer
err
:=
Marshal
(
&
buf
,
tt
.
val
)
if
err
!=
nil
{
t
.
Fatalf
(
"Marshal(%T): %s"
,
tt
.
val
,
err
)
}
s
:=
buf
.
String
()
if
s
!=
tt
.
out
{
t
.
Errorf
(
"Marshal(%T) = %q, want %q
\n
"
,
tt
.
val
,
s
,
tt
.
out
)
}
}
}
type
marshalIndentTest
struct
{
val
interface
{}
indent
string
out
string
}
const
marshalIndentTest1
=
`[
1,
2,
3,
4
]
`
const
marshalIndentTest2
=
`[
[
1,
2
],
[
3,
4
]
]
`
const
marshalIndentTest3
=
`[
[
1,
2
],
[
3,
4
]
]
`
const
marshalIndentTest4
=
`[
[
1,
2
],
[
3,
4
]
]
`
const
marshalIndentTest5
=
`{
"a":1,
"b":"hello"
}
`
const
marshalIndentTest6
=
`{
"3":[
1,
2,
3
]
}
`
var
marshalIndentTests
=
[]
marshalIndentTest
{
marshalIndentTest
{[]
int
{
1
,
2
,
3
,
4
},
" "
,
marshalIndentTest1
},
marshalIndentTest
{[][]
int
{[]
int
{
1
,
2
},
[]
int
{
3
,
4
}},
""
,
marshalIndentTest2
},
marshalIndentTest
{[][]
int
{[]
int
{
1
,
2
},
[]
int
{
3
,
4
}},
" "
,
marshalIndentTest3
},
marshalIndentTest
{[][]
int
{[]
int
{
1
,
2
},
[]
int
{
3
,
4
}},
" "
,
marshalIndentTest4
},
marshalIndentTest
{
struct
{
a
int
b
string
}{
1
,
"hello"
},
" "
,
marshalIndentTest5
,
},
marshalIndentTest
{
map
[
string
][]
int
{
"3"
:
[]
int
{
1
,
2
,
3
}},
" "
,
marshalIndentTest6
},
}
func
TestMarshalIndent
(
t
*
testing
.
T
)
{
for
_
,
tt
:=
range
marshalIndentTests
{
var
buf
bytes
.
Buffer
err
:=
MarshalIndent
(
&
buf
,
tt
.
val
,
tt
.
indent
)
if
err
!=
nil
{
t
.
Fatalf
(
"MarshalIndent(%v): %s"
,
tt
.
val
,
err
)
}
s
:=
buf
.
String
()
if
s
!=
tt
.
out
{
t
.
Errorf
(
"MarshalIndent(%v) = %q, want %q
\n
"
,
tt
.
val
,
s
,
tt
.
out
)
}
}
}
type
marshalErrorTest
struct
{
val
interface
{}
error
string
}
type
ChanVal
struct
{
C
chan
int
}
var
marshalErrorTests
=
[]
marshalErrorTest
{
marshalErrorTest
{
map
[
chan
int
]
string
{
make
(
chan
int
)
:
"one"
},
"json cannot encode value of type map[chan int] string"
},
marshalErrorTest
{
make
(
chan
int
,
100
),
"json cannot encode value of type chan int"
},
marshalErrorTest
{
new
(
ChanVal
),
"json cannot encode value of type chan int"
},
}
func
TestMarshalError
(
t
*
testing
.
T
)
{
for
_
,
tt
:=
range
marshalErrorTests
{
var
buf
bytes
.
Buffer
err
:=
Marshal
(
&
buf
,
tt
.
val
)
if
err
==
nil
{
t
.
Fatalf
(
"Marshal(%T): no error, want error %s"
,
tt
.
val
,
tt
.
error
)
}
if
err
.
String
()
!=
tt
.
error
{
t
.
Fatalf
(
"Marshal(%T) = error %s, want error %s"
,
tt
.
val
,
err
,
tt
.
error
)
}
}
}
src/pkg/template/template_test.go
View file @
dba9d62b
...
@@ -415,7 +415,7 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
...
@@ -415,7 +415,7 @@ func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
s
.
false
=
false
s
.
false
=
false
s
.
mp
=
make
(
map
[
string
]
string
)
s
.
mp
=
make
(
map
[
string
]
string
)
s
.
mp
[
"mapkey"
]
=
"Ahoy!"
s
.
mp
[
"mapkey"
]
=
"Ahoy!"
s
.
json
,
_
=
json
.
Decode
(
"{
\"
maps
\"
:[{
\"
a
\"
:1,
\"
b
\"
:2},{
\"
a
\"
:3,
\"
b
\"
:4}]}"
)
json
.
Unmarshal
([]
byte
(
`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`
),
&
s
.
json
)
s
.
innermap
.
mp
=
make
(
map
[
string
]
int
)
s
.
innermap
.
mp
=
make
(
map
[
string
]
int
)
s
.
innermap
.
mp
[
"innerkey"
]
=
55
s
.
innermap
.
mp
[
"innerkey"
]
=
55
s
.
stringmap
=
make
(
map
[
string
]
string
)
s
.
stringmap
=
make
(
map
[
string
]
string
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment