github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/json/decode_test.gno (about)

     1  package json
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"testing"
     7  )
     8  
     9  type testNode struct {
    10  	name  string
    11  	input []byte
    12  	_type ValueType
    13  	value []byte
    14  }
    15  
    16  func simpleValid(test *testNode, t *testing.T) {
    17  	root, err := Unmarshal(test.input)
    18  	if err != nil {
    19  		t.Errorf("Error on Unmarshal(%s): %s", test.input, err.Error())
    20  	} else if root == nil {
    21  		t.Errorf("Error on Unmarshal(%s): root is nil", test.name)
    22  	} else if root.nodeType != test._type {
    23  		t.Errorf("Error on Unmarshal(%s): wrong type", test.name)
    24  	} else if !bytes.Equal(root.source(), test.value) {
    25  		t.Errorf("Error on Unmarshal(%s): %s != %s", test.name, root.source(), test.value)
    26  	}
    27  }
    28  
    29  func simpleInvalid(test *testNode, t *testing.T) {
    30  	root, err := Unmarshal(test.input)
    31  	if err == nil {
    32  		t.Errorf("Error on Unmarshal(%s): error expected, got '%s'", test.name, root.source())
    33  	} else if root != nil {
    34  		t.Errorf("Error on Unmarshal(%s): root is not nil", test.name)
    35  	}
    36  }
    37  
    38  func simpleCorrupted(name string) *testNode {
    39  	return &testNode{name: name, input: []byte(name)}
    40  }
    41  
    42  func TestUnmarshal_StringSimpleSuccess(t *testing.T) {
    43  	tests := []*testNode{
    44  		{name: "blank", input: []byte("\"\""), _type: String, value: []byte("\"\"")},
    45  		{name: "char", input: []byte("\"c\""), _type: String, value: []byte("\"c\"")},
    46  		{name: "word", input: []byte("\"cat\""), _type: String, value: []byte("\"cat\"")},
    47  		{name: "spaces", input: []byte("  \"good cat or dog\"\r\n "), _type: String, value: []byte("\"good cat or dog\"")},
    48  		{name: "backslash", input: []byte("\"good \\\"cat\\\"\""), _type: String, value: []byte("\"good \\\"cat\\\"\"")},
    49  		{name: "backslash 2", input: []byte("\"good \\\\\\\"cat\\\"\""), _type: String, value: []byte("\"good \\\\\\\"cat\\\"\"")},
    50  	}
    51  	for _, test := range tests {
    52  		t.Run(test.name, func(t *testing.T) {
    53  			simpleValid(test, t)
    54  		})
    55  	}
    56  }
    57  
    58  func TestUnmarshal_NumericSimpleSuccess(t *testing.T) {
    59  	tests := []*testNode{
    60  		{name: "1", input: []byte("1"), _type: Number, value: []byte("1")},
    61  		{name: "-1", input: []byte("-1"), _type: Number, value: []byte("-1")},
    62  
    63  		{name: "1234567890", input: []byte("1234567890"), _type: Number, value: []byte("1234567890")},
    64  		{name: "-123", input: []byte("-123"), _type: Number, value: []byte("-123")},
    65  
    66  		{name: "123.456", input: []byte("123.456"), _type: Number, value: []byte("123.456")},
    67  		{name: "-123.456", input: []byte("-123.456"), _type: Number, value: []byte("-123.456")},
    68  
    69  		{name: "1e3", input: []byte("1e3"), _type: Number, value: []byte("1e3")},
    70  		{name: "1e+3", input: []byte("1e+3"), _type: Number, value: []byte("1e+3")},
    71  		{name: "1e-3", input: []byte("1e-3"), _type: Number, value: []byte("1e-3")},
    72  		{name: "-1e3", input: []byte("-1e3"), _type: Number, value: []byte("-1e3")},
    73  		{name: "-1e-3", input: []byte("-1e-3"), _type: Number, value: []byte("-1e-3")},
    74  
    75  		{name: "1.123e3456", input: []byte("1.123e3456"), _type: Number, value: []byte("1.123e3456")},
    76  		{name: "1.123e-3456", input: []byte("1.123e-3456"), _type: Number, value: []byte("1.123e-3456")},
    77  		{name: "-1.123e3456", input: []byte("-1.123e3456"), _type: Number, value: []byte("-1.123e3456")},
    78  		{name: "-1.123e-3456", input: []byte("-1.123e-3456"), _type: Number, value: []byte("-1.123e-3456")},
    79  
    80  		{name: "1E3", input: []byte("1E3"), _type: Number, value: []byte("1E3")},
    81  		{name: "1E-3", input: []byte("1E-3"), _type: Number, value: []byte("1E-3")},
    82  		{name: "-1E3", input: []byte("-1E3"), _type: Number, value: []byte("-1E3")},
    83  		{name: "-1E-3", input: []byte("-1E-3"), _type: Number, value: []byte("-1E-3")},
    84  
    85  		{name: "1.123E3456", input: []byte("1.123E3456"), _type: Number, value: []byte("1.123E3456")},
    86  		{name: "1.123E-3456", input: []byte("1.123E-3456"), _type: Number, value: []byte("1.123E-3456")},
    87  		{name: "-1.123E3456", input: []byte("-1.123E3456"), _type: Number, value: []byte("-1.123E3456")},
    88  		{name: "-1.123E-3456", input: []byte("-1.123E-3456"), _type: Number, value: []byte("-1.123E-3456")},
    89  
    90  		{name: "-1.123E-3456 with spaces", input: []byte(" \r -1.123E-3456 \t\n"), _type: Number, value: []byte("-1.123E-3456")},
    91  	}
    92  	for _, test := range tests {
    93  		t.Run(test.name, func(t *testing.T) {
    94  			root, err := Unmarshal(test.input)
    95  			if err != nil {
    96  				t.Errorf("Error on Unmarshal(%s): %s", test.name, err.Error())
    97  			} else if root == nil {
    98  				t.Errorf("Error on Unmarshal(%s): root is nil", test.name)
    99  			} else if root.nodeType != test._type {
   100  				t.Errorf("Error on Unmarshal(%s): wrong type", test.name)
   101  			} else if !bytes.Equal(root.source(), test.value) {
   102  				t.Errorf("Error on Unmarshal(%s): %s != %s", test.name, root.source(), test.value)
   103  			}
   104  		})
   105  	}
   106  }
   107  
   108  func TestUnmarshal_StringSimpleCorrupted(t *testing.T) {
   109  	tests := []*testNode{
   110  		{name: "white NL", input: []byte("\"foo\nbar\"")},
   111  		{name: "white R", input: []byte("\"foo\rbar\"")},
   112  		{name: "white Tab", input: []byte("\"foo\tbar\"")},
   113  		{name: "wrong quotes", input: []byte("'cat'")},
   114  		{name: "double string", input: []byte("\"Hello\" \"World\"")},
   115  		{name: "quotes in quotes", input: []byte("\"good \"cat\"\"")},
   116  	}
   117  	for _, test := range tests {
   118  		t.Run(test.name, func(t *testing.T) {
   119  			simpleInvalid(test, t)
   120  		})
   121  	}
   122  }
   123  
   124  func TestUnmarshal_ObjectSimpleSuccess(t *testing.T) {
   125  	tests := []*testNode{
   126  		{name: "{}", input: []byte("{}"), _type: Object, value: []byte("{}")},
   127  		{name: `{ \r\n }`, input: []byte("{ \r\n }"), _type: Object, value: []byte("{ \r\n }")},
   128  		{name: `{"key":1}`, input: []byte(`{"key":1}`), _type: Object, value: []byte(`{"key":1}`)},
   129  		{name: `{"key":true}`, input: []byte(`{"key":true}`), _type: Object, value: []byte(`{"key":true}`)},
   130  		{name: `{"key":"value"}`, input: []byte(`{"key":"value"}`), _type: Object, value: []byte(`{"key":"value"}`)},
   131  		{name: `{"foo":"bar","baz":"foo"}`, input: []byte(`{"foo":"bar", "baz":"foo"}`), _type: Object, value: []byte(`{"foo":"bar", "baz":"foo"}`)},
   132  		{name: "spaces", input: []byte(`  {  "foo"  :  "bar"  , "baz"   :   "foo"   }    `), _type: Object, value: []byte(`{  "foo"  :  "bar"  , "baz"   :   "foo"   }`)},
   133  		{name: "nested", input: []byte(`{"foo":{"bar":{"baz":{}}}}`), _type: Object, value: []byte(`{"foo":{"bar":{"baz":{}}}}`)},
   134  		{name: "array", input: []byte(`{"array":[{},{},{"foo":[{"bar":["baz"]}]}]}`), _type: Object, value: []byte(`{"array":[{},{},{"foo":[{"bar":["baz"]}]}]}`)},
   135  	}
   136  
   137  	for _, test := range tests {
   138  		t.Run(test.name, func(t *testing.T) {
   139  			simpleValid(test, t)
   140  		})
   141  	}
   142  }
   143  
   144  func TestUnmarshal_ObjectSimpleCorrupted(t *testing.T) {
   145  	tests := []*testNode{
   146  		simpleCorrupted("{{{\"key\": \"foo\"{{{{"),
   147  		simpleCorrupted("}"),
   148  		simpleCorrupted("{ }}}}}}}"),
   149  		simpleCorrupted(" }"),
   150  		simpleCorrupted("{,}"),
   151  		simpleCorrupted("{:}"),
   152  		simpleCorrupted("{100000}"),
   153  		simpleCorrupted("{1:1}"),
   154  		simpleCorrupted("{'1:2,3:4'}"),
   155  		simpleCorrupted(`{"d"}`),
   156  		simpleCorrupted(`{"foo"}`),
   157  		simpleCorrupted(`{"foo":}`),
   158  		simpleCorrupted(`{:"foo"}`),
   159  		simpleCorrupted(`{"foo":bar}`),
   160  		simpleCorrupted(`{"foo":"bar",}`),
   161  		simpleCorrupted(`{}{}`),
   162  		simpleCorrupted(`{},{}`),
   163  		simpleCorrupted(`{[},{]}`),
   164  		simpleCorrupted(`{[,]}`),
   165  		simpleCorrupted(`{[]}`),
   166  		simpleCorrupted(`{}1`),
   167  		simpleCorrupted(`1{}`),
   168  		simpleCorrupted(`{"x"::1}`),
   169  		simpleCorrupted(`{null:null}`),
   170  		simpleCorrupted(`{"foo:"bar"}`),
   171  	}
   172  
   173  	for _, test := range tests {
   174  		t.Run(test.name, func(t *testing.T) {
   175  			simpleInvalid(test, t)
   176  		})
   177  	}
   178  }
   179  
   180  func TestUnmarshal_NullSimpleCorrupted(t *testing.T) {
   181  	tests := []*testNode{
   182  		{name: "nul", input: []byte("nul")},
   183  		{name: "nil", input: []byte("nil")},
   184  		{name: "nill", input: []byte("nill")},
   185  		{name: "NILL", input: []byte("NILL")},
   186  		{name: "Null", input: []byte("Null")},
   187  		{name: "NULL", input: []byte("NULL")},
   188  		{name: "spaces", input: []byte("Nu ll")},
   189  		{name: "null1", input: []byte("null1")},
   190  		{name: "double", input: []byte("null null")},
   191  	}
   192  
   193  	for _, test := range tests {
   194  		t.Run(test.name, func(t *testing.T) {
   195  			simpleInvalid(test, t)
   196  		})
   197  	}
   198  }
   199  
   200  func TestUnmarshal_BoolSimpleSuccess(t *testing.T) {
   201  	tests := []*testNode{
   202  		{name: "lower true", input: []byte("true"), _type: Boolean, value: []byte("true")},
   203  		{name: "lower false", input: []byte("false"), _type: Boolean, value: []byte("false")},
   204  		{name: "spaces true", input: []byte("  true\r\n "), _type: Boolean, value: []byte("true")},
   205  		{name: "spaces false", input: []byte("  false\r\n "), _type: Boolean, value: []byte("false")},
   206  	}
   207  
   208  	for _, test := range tests {
   209  		t.Run(test.name, func(t *testing.T) {
   210  			simpleValid(test, t)
   211  		})
   212  	}
   213  }
   214  
   215  func TestUnmarshal_BoolSimpleCorrupted(t *testing.T) {
   216  	tests := []*testNode{
   217  		simpleCorrupted("tru"),
   218  		simpleCorrupted("fals"),
   219  		simpleCorrupted("tre"),
   220  		simpleCorrupted("fal se"),
   221  		simpleCorrupted("true false"),
   222  		simpleCorrupted("True"),
   223  		simpleCorrupted("TRUE"),
   224  		simpleCorrupted("False"),
   225  		simpleCorrupted("FALSE"),
   226  	}
   227  
   228  	for _, test := range tests {
   229  		t.Run(test.name, func(t *testing.T) {
   230  			simpleInvalid(test, t)
   231  		})
   232  	}
   233  }
   234  
   235  func TestUnmarshal_ArraySimpleSuccess(t *testing.T) {
   236  	tests := []*testNode{
   237  		{name: "[]", input: []byte("[]"), _type: Array, value: []byte("[]")},
   238  		{name: "[1]", input: []byte("[1]"), _type: Array, value: []byte("[1]")},
   239  		{name: "[1,2,3]", input: []byte("[1,2,3]"), _type: Array, value: []byte("[1,2,3]")},
   240  		{name: "[1, 2, 3]", input: []byte("[1, 2, 3]"), _type: Array, value: []byte("[1, 2, 3]")},
   241  		{name: "[1,[2],3]", input: []byte("[1,[2],3]"), _type: Array, value: []byte("[1,[2],3]")},
   242  		{name: "[[],[],[]]", input: []byte("[[],[],[]]"), _type: Array, value: []byte("[[],[],[]]")},
   243  		{name: "[[[[[]]]]]", input: []byte("[[[[[]]]]]"), _type: Array, value: []byte("[[[[[]]]]]")},
   244  		{name: "[true,null,1,\"foo\",[]]", input: []byte("[true,null,1,\"foo\",[]]"), _type: Array, value: []byte("[true,null,1,\"foo\",[]]")},
   245  		{name: "spaces", input: []byte("\n\r [\n1\n ]\r\n"), _type: Array, value: []byte("[\n1\n ]")},
   246  	}
   247  
   248  	for _, test := range tests {
   249  		t.Run(test.name, func(t *testing.T) {
   250  			simpleValid(test, t)
   251  		})
   252  	}
   253  }
   254  
   255  func TestUnmarshal_ArraySimpleCorrupted(t *testing.T) {
   256  	tests := []*testNode{
   257  		simpleCorrupted("[,]"),
   258  		simpleCorrupted("[]\\"),
   259  		simpleCorrupted("[1,]"),
   260  		simpleCorrupted("[[]"),
   261  		simpleCorrupted("[]]"),
   262  		simpleCorrupted("1[]"),
   263  		simpleCorrupted("[]1"),
   264  		simpleCorrupted("[[]1]"),
   265  	}
   266  
   267  	for _, test := range tests {
   268  		t.Run(test.name, func(t *testing.T) {
   269  			simpleInvalid(test, t)
   270  		})
   271  	}
   272  }
   273  
   274  // Examples from https://json.org/example.html
   275  func TestUnmarshal(t *testing.T) {
   276  	tests := []struct {
   277  		name  string
   278  		value string
   279  	}{
   280  		{
   281  			name: "glossary",
   282  			value: `{
   283  				"glossary": {
   284  					"title": "example glossary",
   285  					"GlossDiv": {
   286  						"title": "S",
   287  						"GlossList": {
   288  							"GlossEntry": {
   289  								"ID": "SGML",
   290  								"SortAs": "SGML",
   291  								"GlossTerm": "Standard Generalized Markup Language",
   292  								"Acronym": "SGML",
   293  								"Abbrev": "ISO 8879:1986",
   294  								"GlossDef": {
   295  									"para": "A meta-markup language, used to create markup languages such as DocBook.",
   296  									"GlossSeeAlso": ["GML", "XML"]
   297  								},
   298  								"GlossSee": "markup"
   299  							}
   300  						}
   301  					}
   302  				}
   303  			}`,
   304  		},
   305  		{
   306  			name: "menu",
   307  			value: `{"menu": {
   308  				"id": "file",
   309  				"value": "File",
   310  				"popup": {
   311  				  "menuitem": [
   312  					{"value": "New", "onclick": "CreateNewDoc()"},
   313  					{"value": "Open", "onclick": "OpenDoc()"},
   314  					{"value": "Close", "onclick": "CloseDoc()"}
   315  				  ]
   316  				}
   317  			}}`,
   318  		},
   319  		{
   320  			name: "widget",
   321  			value: `{"widget": {
   322  				"debug": "on",
   323  				"window": {
   324  					"title": "Sample Konfabulator Widget",
   325  					"name": "main_window",
   326  					"width": 500,
   327  					"height": 500
   328  				},
   329  				"image": { 
   330  					"src": "Images/Sun.png",
   331  					"name": "sun1",
   332  					"hOffset": 250,
   333  					"vOffset": 250,
   334  					"alignment": "center"
   335  				},
   336  				"text": {
   337  					"data": "Click Here",
   338  					"size": 36,
   339  					"style": "bold",
   340  					"name": "text1",
   341  					"hOffset": 250,
   342  					"vOffset": 100,
   343  					"alignment": "center",
   344  					"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
   345  				}
   346  			}}    `,
   347  		},
   348  		{
   349  			name: "web-app",
   350  			value: `{"web-app": {
   351  				"servlet": [   
   352  				  {
   353  					"servlet-name": "cofaxCDS",
   354  					"servlet-class": "org.cofax.cds.CDSServlet",
   355  					"init-param": {
   356  					  "configGlossary:installationAt": "Philadelphia, PA",
   357  					  "configGlossary:adminEmail": "ksm@pobox.com",
   358  					  "configGlossary:poweredBy": "Cofax",
   359  					  "configGlossary:poweredByIcon": "/images/cofax.gif",
   360  					  "configGlossary:staticPath": "/content/static",
   361  					  "templateProcessorClass": "org.cofax.WysiwygTemplate",
   362  					  "templateLoaderClass": "org.cofax.FilesTemplateLoader",
   363  					  "templatePath": "templates",
   364  					  "templateOverridePath": "",
   365  					  "defaultListTemplate": "listTemplate.htm",
   366  					  "defaultFileTemplate": "articleTemplate.htm",
   367  					  "useJSP": false,
   368  					  "jspListTemplate": "listTemplate.jsp",
   369  					  "jspFileTemplate": "articleTemplate.jsp",
   370  					  "cachePackageTagsTrack": 200,
   371  					  "cachePackageTagsStore": 200,
   372  					  "cachePackageTagsRefresh": 60,
   373  					  "cacheTemplatesTrack": 100,
   374  					  "cacheTemplatesStore": 50,
   375  					  "cacheTemplatesRefresh": 15,
   376  					  "cachePagesTrack": 200,
   377  					  "cachePagesStore": 100,
   378  					  "cachePagesRefresh": 10,
   379  					  "cachePagesDirtyRead": 10,
   380  					  "searchEngineListTemplate": "forSearchEnginesList.htm",
   381  					  "searchEngineFileTemplate": "forSearchEngines.htm",
   382  					  "searchEngineRobotsDb": "WEB-INF/robots.db",
   383  					  "useDataStore": true,
   384  					  "dataStoreClass": "org.cofax.SqlDataStore",
   385  					  "redirectionClass": "org.cofax.SqlRedirection",
   386  					  "dataStoreName": "cofax",
   387  					  "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
   388  					  "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
   389  					  "dataStoreUser": "sa",
   390  					  "dataStorePassword": "dataStoreTestQuery",
   391  					  "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
   392  					  "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
   393  					  "dataStoreInitConns": 10,
   394  					  "dataStoreMaxConns": 100,
   395  					  "dataStoreConnUsageLimit": 100,
   396  					  "dataStoreLogLevel": "debug",
   397  					  "maxUrlLength": 500}},
   398  				  {
   399  					"servlet-name": "cofaxEmail",
   400  					"servlet-class": "org.cofax.cds.EmailServlet",
   401  					"init-param": {
   402  					"mailHost": "mail1",
   403  					"mailHostOverride": "mail2"}},
   404  				  {
   405  					"servlet-name": "cofaxAdmin",
   406  					"servlet-class": "org.cofax.cds.AdminServlet"},
   407  			   
   408  				  {
   409  					"servlet-name": "fileServlet",
   410  					"servlet-class": "org.cofax.cds.FileServlet"},
   411  				  {
   412  					"servlet-name": "cofaxTools",
   413  					"servlet-class": "org.cofax.cms.CofaxToolsServlet",
   414  					"init-param": {
   415  					  "templatePath": "toolstemplates/",
   416  					  "log": 1,
   417  					  "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
   418  					  "logMaxSize": "",
   419  					  "dataLog": 1,
   420  					  "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
   421  					  "dataLogMaxSize": "",
   422  					  "removePageCache": "/content/admin/remove?cache=pages&id=",
   423  					  "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
   424  					  "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
   425  					  "lookInContext": 1,
   426  					  "adminGroupID": 4,
   427  					  "betaServer": true}}],
   428  				"servlet-mapping": {
   429  				  "cofaxCDS": "/",
   430  				  "cofaxEmail": "/cofaxutil/aemail/*",
   431  				  "cofaxAdmin": "/admin/*",
   432  				  "fileServlet": "/static/*",
   433  				  "cofaxTools": "/tools/*"},
   434  			   
   435  				"taglib": {
   436  				  "taglib-uri": "cofax.tld",
   437  				  "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}`,
   438  		},
   439  		{
   440  			name: "SVG Viewer",
   441  			value: `{"menu": {
   442  				"header": "SVG Viewer",
   443  				"items": [
   444  					{"id": "Open"},
   445  					{"id": "OpenNew", "label": "Open New"},
   446  					null,
   447  					{"id": "ZoomIn", "label": "Zoom In"},
   448  					{"id": "ZoomOut", "label": "Zoom Out"},
   449  					{"id": "OriginalView", "label": "Original View"},
   450  					null,
   451  					{"id": "Quality"},
   452  					{"id": "Pause"},
   453  					{"id": "Mute"},
   454  					null,
   455  					{"id": "Find", "label": "Find..."},
   456  					{"id": "FindAgain", "label": "Find Again"},
   457  					{"id": "Copy"},
   458  					{"id": "CopyAgain", "label": "Copy Again"},
   459  					{"id": "CopySVG", "label": "Copy SVG"},
   460  					{"id": "ViewSVG", "label": "View SVG"},
   461  					{"id": "ViewSource", "label": "View Source"},
   462  					{"id": "SaveAs", "label": "Save As"},
   463  					null,
   464  					{"id": "Help"},
   465  					{"id": "About", "label": "About Adobe CVG Viewer..."}
   466  				]
   467  			}}`,
   468  		},
   469  	}
   470  	for _, test := range tests {
   471  		t.Run(test.name, func(t *testing.T) {
   472  			_, err := Unmarshal([]byte(test.value))
   473  			if err != nil {
   474  				t.Errorf("Error on Unmarshal: %s", err.Error())
   475  			}
   476  		})
   477  	}
   478  }
   479  
   480  func TestUnmarshalSafe(t *testing.T) {
   481  	json := []byte(`{ "store": {
   482  		"book": [ 
   483  		  { "category": "reference",
   484  			"author": "Nigel Rees",
   485  			"title": "Sayings of the Century",
   486  			"price": 8.95
   487  		  },
   488  		  { "category": "fiction",
   489  			"author": "Evelyn Waugh",
   490  			"title": "Sword of Honour",
   491  			"price": 12.99
   492  		  },
   493  		  { "category": "fiction",
   494  			"author": "Herman Melville",
   495  			"title": "Moby Dick",
   496  			"isbn": "0-553-21311-3",
   497  			"price": 8.99
   498  		  },
   499  		  { "category": "fiction",
   500  			"author": "J. R. R. Tolkien",
   501  			"title": "The Lord of the Rings",
   502  			"isbn": "0-395-19395-8",
   503  			"price": 22.99
   504  		  }
   505  		],
   506  		"bicycle": {
   507  		  "color": "red",
   508  		  "price": 19.95
   509  		}
   510  	  }
   511  	}`)
   512  	safe, err := UnmarshalSafe(json)
   513  	if err != nil {
   514  		t.Errorf("Error on Unmarshal: %s", err.Error())
   515  	} else if safe == nil {
   516  		t.Errorf("Error on Unmarshal: safe is nil")
   517  	} else {
   518  		root, err := Unmarshal(json)
   519  		if err != nil {
   520  			t.Errorf("Error on Unmarshal: %s", err.Error())
   521  		} else if root == nil {
   522  			t.Errorf("Error on Unmarshal: root is nil")
   523  		} else if !bytes.Equal(root.source(), safe.source()) {
   524  			t.Errorf("Error on UnmarshalSafe: values not same")
   525  		}
   526  	}
   527  }
   528  
   529  // BenchmarkGoStdUnmarshal-8   	   61698	     19350 ns/op	     288 B/op	       6 allocs/op
   530  // BenchmarkUnmarshal-8        	   45620	     26165 ns/op	   21889 B/op	     367 allocs/op
   531  //
   532  // type bench struct {
   533  // 	Name  string `json:"name"`
   534  // 	Value int    `json:"value"`
   535  // }
   536  
   537  // func BenchmarkGoStdUnmarshal(b *testing.B) {
   538  // 	data := []byte(webApp)
   539  // 	for i := 0; i < b.N; i++ {
   540  // 		err := json.Unmarshal(data, &bench{})
   541  // 		if err != nil {
   542  // 			b.Fatal(err)
   543  // 		}
   544  // 	}
   545  // }
   546  
   547  // func BenchmarkUnmarshal(b *testing.B) {
   548  // 	data := []byte(webApp)
   549  // 	for i := 0; i < b.N; i++ {
   550  // 		_, err := Unmarshal(data)
   551  // 		if err != nil {
   552  // 			b.Fatal(err)
   553  // 		}
   554  // 	}
   555  // }