github.com/jn0/go-json@v0.1.0/json_test.go (about)

     1  package json
     2  
     3  import "testing"
     4  import "github.com/stretchr/testify/assert"
     5  
     6  import ( // for Example*
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  func BenchmarkAll(b *testing.B) {
    15  	b.ResetTimer()
    16  	for i := 0; i < 1000; i++ {
    17  		ParseValue(source)
    18  	}
    19  }
    20  
    21  func ExampleUptime() {
    22  	// Suppose you have to feed some data to a monitor.
    23  	// The API makes you to use JSON.
    24  	// One of the monitored values is system uptime.
    25  
    26  	// Read the data from `procfs(5)` (or run `uptime(1)` and catch its output)
    27  	const uptime = "/proc/uptime"
    28  	data, err := ioutil.ReadFile(uptime)
    29  	if err != nil {
    30  		fmt.Fprintf(os.Stderr, "ioutil.ReadFile(%+q): %v", uptime, err)
    31  		return // handle file access/read error here
    32  	}
    33  	// It should arrive as something like "3294591.50 12242861.60\n",
    34  	// where the first token is uptime (the 2nd one we wont use).
    35  
    36  	word := strings.Split(strings.TrimSpace(string(data)), " ")
    37  	if len(word) != 2 {
    38  		fmt.Fprintf(os.Stderr, "Garbage read from %+q: %v", uptime, data)
    39  		return // not much one can do if there is a "syntax error"...
    40  	}
    41  
    42  	// Use these values instead of "stable" fakes below
    43  	now := time.Now().UTC().Unix() // an integer
    44  	val := word[0]                 // a string (float will be parsed)
    45  
    46  	now = 1576839878    // fake
    47  	val = "3295164.960" // fake; still use string here, a "real" float would be ok too
    48  
    49  	report := new(JsonObject)                  // The report.
    50  	report.Insert("time", NewJsonInt(now))     // Add time stamp.
    51  	report.Insert("uptime", NewJsonFloat(val)) // Add the value reported.
    52  
    53  	fmt.Println(report.Json()) // Produce JSON text...
    54  	// Output:
    55  	// { "time": 1576839878, "uptime": 3295164.960000 }
    56  }
    57  
    58  func TestPanics(t *testing.T) {
    59  	// The only parser that panics is parseString for wrong \uXXXX things.
    60  
    61  	i1 := new(JsonInt)
    62  	assert.Panics(t, func() { i1.Set(123.123) }, "Int.Set(Float)")
    63  	assert.Panics(t, func() { i1.Append(123) }, "Int.Append()")
    64  	assert.Panics(t, func() { i1.Insert("xyz", 123) }, "Int.Insert()")
    65  
    66  	f1 := new(JsonFloat)
    67  	assert.Panics(t, func() { f1.Set(123) }, "Float.Set(Int)")
    68  	assert.Panics(t, func() { f1.Append(123.123) }, "Float.Append()")
    69  	assert.Panics(t, func() { f1.Insert("xyz", 123.123) }, "Float.Insert()")
    70  
    71  	b1 := new(JsonBool)
    72  	assert.Panics(t, func() { b1.Set(123.123) }, "Bool.Set(Float)")
    73  	assert.Panics(t, func() { b1.Parse("never") }, "Bool.Parse(garbage)")
    74  	assert.Panics(t, func() { b1.Append(true) }, "Bool.Append()")
    75  	assert.Panics(t, func() { b1.Insert("xyz", true) }, "Bool.Insert()")
    76  
    77  	s1 := new(JsonString)
    78  	assert.Panics(t, func() { s1.Set(123.123) }, "String.Set(Float)")
    79  	assert.Panics(t, func() { s1.Append("123") }, "String.Append()")
    80  	assert.Panics(t, func() { s1.Insert("xyz", "123") }, "String.Insert()")
    81  	assert.Panics(t, func() { s1.Parse(`"zzz\u123zzz"`) }, `String.Parse("\u123z")`)
    82  
    83  	a1 := new(JsonArray)
    84  	assert.Panics(t, func() { a1.Set(123.123) }, "Array.Set(Float)")
    85  	assert.Panics(t, func() { a1.Insert("xyz", 123) }, "Array.Insert()")
    86  
    87  	o1 := new(JsonObject)
    88  	assert.Panics(t, func() { o1.Set(123.123) }, "Object.Set(Float)")
    89  	assert.Panics(t, func() { o1.Append(123) }, "Object.Append()")
    90  	assert.Panics(t, func() { o1.Insert("xyz", o1) }, "Object looped")
    91  
    92  	t.Logf("All panics performed")
    93  }
    94  
    95  func TestValues(t *testing.T) {
    96  
    97  	var is = 12345
    98  	i1 := NewJsonInt(is)
    99  	i2 := new(JsonInt)
   100  	var i0 *JsonInt
   101  	if i0.Json() != "null" {
   102  		t.Errorf("int: %q != null", i0.Json())
   103  	}
   104  	if e := i2.Parse(i1.Json()); e != nil {
   105  		t.Errorf("int: Parse(%+q): %v", i1.Json(), e)
   106  	}
   107  	if !i1.Equal(i2) {
   108  		t.Errorf("int: !parse.Equal(json): %q != %q", i1.Json(), i2.Json())
   109  	}
   110  	if i1.Json() != i2.Json() {
   111  		t.Errorf("int: parse != json: %q != %q", i1.Json(), i2.Json())
   112  	}
   113  	i1.Set(int8(123))
   114  	i2.Set(int32(123))
   115  	if !i1.Equal(i2) {
   116  		t.Errorf("int: !Equal(): %q != %q", i1.Json(), i2.Json())
   117  	}
   118  	i1.Set(int(12388))
   119  	i2.Set(int16(12388))
   120  	if !i1.Equal(i2) {
   121  		t.Errorf("int: !Equal(): %q != %q", i1.Json(), i2.Json())
   122  	}
   123  	i1.Set(int(12399))
   124  	i2.Set("12399")
   125  	if !i1.Equal(i2) {
   126  		t.Errorf("int: !Equal(): %q != %q", i1.Json(), i2.Json())
   127  	}
   128  	i1.Set(int64(111))
   129  	i2.Set(222)
   130  	if i1.Equal(i2) {
   131  		t.Errorf("int: Equal(): %q == %q", i1.Json(), i2.Json())
   132  	}
   133  	if i1.Equal(new(JsonFloat)) {
   134  		t.Errorf("int: Equal(): %q == Float", i1.Json())
   135  	}
   136  
   137  	var f0 *JsonFloat
   138  	if f0.Json() != "null" {
   139  		t.Errorf("float: %q != null", f0.Json())
   140  	}
   141  	var fs = -3.1
   142  	f1 := NewJsonFloat(fs)
   143  	f2 := new(JsonFloat)
   144  	if e := f2.Parse(f1.Json()); e != nil {
   145  		t.Errorf("string: Parse(%+q): %v", f1.Json(), e)
   146  	}
   147  	if f1.Equal(i1) {
   148  		t.Errorf("float: Equal(int): %q != %q", f1.Json(), i1.Json())
   149  	}
   150  	if !f1.Equal(f2) {
   151  		t.Errorf("float: !parse.Equal(json): %q != %q", f1.Json(), f2.Json())
   152  	}
   153  	if f1.Json() != f2.Json() {
   154  		t.Errorf("float: parse != json: %q != %q", f1.Json(), f2.Json())
   155  	}
   156  	f1.Set(123.2)
   157  	f2.Set("123.2")
   158  	if !f1.Equal(f2) ||
   159  		f1.Value() != 123.2 || f2.Value() != 123.2 ||
   160  		f1.Value() != f2.Value() {
   161  		t.Errorf("float: !Equal(): %q != %q", f1.Json(), f2.Json())
   162  	}
   163  	f1.Set(float32(123.4))
   164  	f2.Set(float64(123.4))
   165  	if !f1.Equal(f2) {
   166  		t.Logf("float: !Equal(): %q=%f != %q=%f (IT HAPPENS)",
   167  			f1.Json(), f1.Value(), f2.Json(), f2.Value())
   168  	}
   169  	if e := f2.Parse("asd"); e == nil {
   170  		t.Errorf("string: Parse(%+q): no error", "asd")
   171  	}
   172  
   173  	var b0 *JsonBool
   174  	if b0.Json() != "null" {
   175  		t.Errorf("float: %q != null", b0.Json())
   176  	}
   177  	var bs = true
   178  	b1 := NewJsonBool(bs)
   179  	b2 := new(JsonBool)
   180  	if e := b2.Parse(b1.Json()); e != nil {
   181  		t.Errorf("string: Parse(%+q): %v", b1.Json(), e)
   182  	}
   183  	if !b1.Equal(b2) || !(b1.Value().(bool)) || !(b2.Value().(bool)) {
   184  		t.Errorf("bool: !parse.Equal(json): %q != %q", b1.Json(), b2.Json())
   185  	}
   186  	if b1.Json() != b2.Json() {
   187  		t.Errorf("bool: parse != json: %q != %q", b1.Json(), b2.Json())
   188  	}
   189  	b1.Set(true)
   190  	b2.Set(!false)
   191  	if !b1.Equal(b2) || !(b1.Value().(bool)) || !(b2.Value().(bool)) {
   192  		t.Errorf("bool: !Equal(): %q != %q", b1.Json(), b2.Json())
   193  	}
   194  	b1.Set("true")
   195  	b2.Set("false")
   196  	if b1.Equal(b2) || !(b1.Value().(bool)) || (b2.Value().(bool)) {
   197  		t.Errorf("bool: Equal(): %q != %q", b1.Json(), b2.Json())
   198  	}
   199  	if b1.Equal(i1) {
   200  		t.Errorf("bool: Equal(Int): %q == %q", b1.Json(), i1.Json())
   201  	}
   202  
   203  	var s0 *JsonString
   204  	if s0.Json() != "null" {
   205  		t.Errorf("string: %q != null", s0.Json())
   206  	}
   207  	var ss = "some string"
   208  	s1 := NewJsonString(ss)
   209  	s2 := new(JsonString)
   210  	if e := s2.Parse(s1.Json()); e != nil {
   211  		t.Errorf("string: Parse(%+q): %v", s1.Json(), e)
   212  	}
   213  	if s1.Equal(i1) {
   214  		t.Errorf("string: Equal(Int): %q != %q", s1.Json(), i1.Json())
   215  	}
   216  	if !s1.Equal(s2) {
   217  		t.Errorf("string: !parse.Equal(json): %q != %q", s1.Json(), s2.Json())
   218  	}
   219  	if s1.Json() != s2.Json() {
   220  		t.Errorf("string: parse != json: %q != %q", s1.Json(), s2.Json())
   221  	}
   222  	if s1.Value() != ss {
   223  		t.Errorf("string: %q != %q", s1.Json(), ss)
   224  	}
   225  	s1.Set("string one")
   226  	s2.Set("string one")
   227  	if !s1.Equal(s2) {
   228  		t.Errorf("string: !Equal(): %q != %q", s1.Json(), s2.Json())
   229  	}
   230  	s2.Parse("\"string one\"")
   231  	if !s1.Equal(s2) {
   232  		t.Errorf("string: !Equal(): %q != %q", s1.Json(), s2.Json())
   233  	}
   234  	if e := s2.Parse(`bad string`); e == nil {
   235  		t.Errorf("string: Parse(garbage) passed")
   236  	}
   237  	if e := s2.Parse(`"bad string"XXX`); e == nil {
   238  		t.Errorf(`string: Parse("string"garbage) passed`)
   239  	}
   240  
   241  	var a0, a2 *JsonArray
   242  	if a0.Json() != "null" {
   243  		t.Errorf("array: %q != null", a0.Json())
   244  	}
   245  	if !a0.Equal(a2) {
   246  		t.Errorf("array: %q != %q", a0.Json(), a2.Json())
   247  	}
   248  	var as = []JsonValue{i1, b1, s1, nil} // don't use floats! they aren't equal
   249  	a1 := NewJsonArray(as)
   250  	a1.Append(NewJsonInt(-35))
   251  	a2 = new(JsonArray)
   252  	if a0.Equal(a1) {
   253  		t.Errorf("array: %q == %q", a0.Json(), a1.Json())
   254  	}
   255  	if !a0.Equal(a2) {
   256  		t.Errorf("array: %q != %q", a0.Json(), a2.Json())
   257  	}
   258  	a1.Value()
   259  	a0 = new(JsonArray)
   260  	if !a0.Equal(a2) {
   261  		t.Errorf("array: %q == %q", a0.Json(), a2.Json())
   262  	}
   263  	if e := a2.Parse(a1.Json()); e != nil {
   264  		t.Errorf("string: Parse(%+q): %v", a1.Json(), e)
   265  	}
   266  	if a1.Equal(i1) {
   267  		t.Errorf("array: %q != %q", a1.Json(), i1.Json())
   268  	}
   269  	if !a1.Equal(a2) {
   270  		t.Errorf("array: !parse.Equal(json): %q != %q", a1.Json(), a2.Json())
   271  	}
   272  	if a1.Json() != a2.Json() {
   273  		t.Errorf("array: parse != json: %q != %q", a1.Json(), a2.Json())
   274  	}
   275  	a1.Append(NewJsonInt(999))
   276  	if a1.Equal(a2) {
   277  		t.Errorf("array: Equal(): %q != %q", a1.Json(), a2.Json())
   278  	}
   279  	a1.Set([]JsonValue{i1, b1, s1, i0})
   280  	if a1.Equal(a2) {
   281  		t.Errorf("array: Equal(): %q == %q", a1.Json(), a2.Json())
   282  	}
   283  	a1.Set([]JsonValue{i1, b1, s1, nil})
   284  	if a1.Equal(a2) {
   285  		t.Errorf("array: Equal(): %q == %q", a1.Json(), a2.Json())
   286  	}
   287  	if a1.Json() == a2.Json() {
   288  		t.Errorf("array: %q == %q", a1.Json(), a2.Json())
   289  	}
   290  	a1 = NewJsonArray([]JsonValue{i1, b1, s1, i1})
   291  	a2 = NewJsonArray([]JsonValue{i1, b1, s1, i2})
   292  	if a1.Equal(a2) {
   293  		fmt.Println(a1.Json())
   294  		fmt.Println(a2.Json())
   295  		t.Errorf("array: Equal(): %q == %q", a1.Json(), a2.Json())
   296  	}
   297  	a1 = NewJsonArray([]JsonValue{i1, b1, s1, i2})
   298  	a2 = NewJsonArray([]JsonValue{i1, b1, s1, nil})
   299  	if a1.Equal(a2) {
   300  		fmt.Println(a1.Json())
   301  		fmt.Println(a2.Json())
   302  		t.Errorf("array: Equal(): %q == %q", a1.Json(), a2.Json())
   303  	}
   304  	a1 = NewJsonArray([]JsonValue{i1, b1, s1, i0})
   305  	a2 = NewJsonArray([]JsonValue{i1, b1, s1, nil})
   306  	if !a1.Equal(a2) {
   307  		fmt.Println(a1.Json())
   308  		fmt.Println(a2.Json())
   309  		t.Errorf("array: Equal(): %q != %q", a1.Json(), a2.Json())
   310  	}
   311  	if e := a0.Parse(`[x]`); e == nil {
   312  		t.Errorf("array: Parse(): no error")
   313  	}
   314  	if e := a0.Parse(`[0],`); e == nil {
   315  		t.Errorf("array: Parse(): no error")
   316  	}
   317  	a1.Set(as)
   318  
   319  	var os = map[string]JsonValue{
   320  		"one":  i1,
   321  		"two":  s1,
   322  		"tree": nil,
   323  		"list": a1,
   324  		"bool": b1,
   325  	}
   326  	var o0 *JsonObject
   327  	o1 := NewJsonObject(os)
   328  	o1.Value()
   329  	// o1.Insert("self", o1) // he-he...
   330  	o2 := new(JsonObject)
   331  	if !o2.IsNull() {
   332  		t.Errorf("object: not (%+q).IsNull()", o2.Json())
   333  	}
   334  	if !o2.Equal(o0) {
   335  		t.Errorf("object: %q != %q", o2.Json(), o0.Json())
   336  	}
   337  	o1.Insert("new", NewJsonInt(-35))
   338  	if o2.Equal(o1) {
   339  		t.Errorf("object: %q == %q", o2.Json(), o1.Json())
   340  	}
   341  	if e := o2.Parse(o1.Json()); e != nil {
   342  		t.Errorf("object: Parse(%+q): %v", o1.Json(), e)
   343  	}
   344  	if !o1.Equal(o2) {
   345  		fmt.Println(o1.Json())
   346  		fmt.Println(o2.Json())
   347  		t.Errorf("object: !parse.Equal(json): %q != %q", o1.Json(), o2.Json())
   348  	}
   349  	o2.Insert("other", o1)
   350  	if o1.Equal(o2) {
   351  		t.Errorf("object: Equal(): %q != %q", o1.Json(), o2.Json())
   352  	}
   353  	if e := o2.Parse(`x`); e == nil {
   354  		t.Errorf("object: Parse(junk): no error")
   355  	}
   356  	if e := o2.Parse(`{"x":1},`); e == nil {
   357  		t.Errorf("object: Parse(tail): no error")
   358  	}
   359  	o2.Set(*o1)
   360  	if !o2.Equal(o1) {
   361  		fmt.Println(o1.Json())
   362  		fmt.Println(o2.Json())
   363  		t.Errorf("object: %q != %q", o2.Json(), o1.Json())
   364  	}
   365  	o2.Set(o1)
   366  	if !o2.Equal(o1) {
   367  		fmt.Println(o1.Json())
   368  		fmt.Println(o2.Json())
   369  		t.Errorf("object: %q != %q", o2.Json(), o1.Json())
   370  	}
   371  	o2.Set(o1.Value())
   372  	if !o2.Equal(o1) {
   373  		fmt.Println(o1.Json())
   374  		fmt.Println(o2.Json())
   375  		t.Errorf("object: %q != %q", o2.Json(), o1.Json())
   376  	}
   377  	o1.Insert("diff", new(JsonInt))
   378  	o2.Insert("diff", NewJsonInt(1))
   379  	if o2.Equal(o1) {
   380  		fmt.Println(o1.Json())
   381  		fmt.Println(o2.Json())
   382  		t.Errorf("object: %q == %q", o2.Json(), o1.Json())
   383  	}
   384  	o2.Set(o1.Value())
   385  	o1.Insert("xx1", NewJsonInt(1))
   386  	o2.Insert("xx2", NewJsonInt(1))
   387  	if o2.Equal(o1) {
   388  		fmt.Println(o1.Json())
   389  		fmt.Println(o2.Json())
   390  		t.Errorf("object: %q == %q", o2.Json(), o1.Json())
   391  	}
   392  
   393  }
   394  
   395  func TestParsers(t *testing.T) {
   396  
   397  	test := func(
   398  		s string,
   399  		f func(string) (JsonValue, string, error),
   400  		eval func(JsonValue, string, error) bool,
   401  	) {
   402  		v, tail, err := f(s)
   403  		ok := eval(v, tail, err)
   404  		x := t.Logf
   405  		if !ok {
   406  			x = t.Errorf
   407  		}
   408  		o := ""
   409  		if v != nil {
   410  			o = v.Json()
   411  		}
   412  		x("s=%q (v=%#v=%s tail=%#v err=%#v) ok=%v", s, v, o, tail, err, ok)
   413  	}
   414  
   415  	noerr := func(v JsonValue, t string, e error) bool { return e == nil }
   416  	erratic := func(v JsonValue, t string, e error) bool { return e != nil }
   417  	notail := func(v JsonValue, t string, e error) bool { return t == "" }
   418  	taily := func(v JsonValue, t string, e error) bool { return t != "" }
   419  	clean := func(v JsonValue, t string, e error) bool { return noerr(v, t, e) && notail(v, t, e) }
   420  
   421  	test(`bad`, parseObject, erratic)
   422  	test(`	bad	`, parseObject, erratic)
   423  	test(`	`, parseObject, erratic)
   424  	test(`{ "simple": "object" }`, parseObject, clean)
   425  	test(` 	{	"simple"	:	"object"	}	`, parseObject, clean)
   426  	test(`{ "simple": "object" }, 1`, parseObject, taily)
   427  	test(`{ "": "object" }, 1`, parseObject, taily)
   428  	test(`{ "simple": "" }, 1`, parseObject, taily)
   429  	test(`{ "better": "object", "one": 1, "null": null, "neg": -2.5 }`, parseObject, clean)
   430  	test(`{ "simple" = "bad object"}`, parseObject, erratic)
   431  	test(`{ "simple": "bad object"`, parseObject, erratic)
   432  	test(`{ "simple": }`, parseObject, erratic)
   433  	test(`{ "simple": `, parseObject, erratic)
   434  	test(`{ "simple" `, parseObject, erratic)
   435  	test(`{ "simple": "bad object }`, parseObject, erratic)
   436  	test(`{ "simple": "bad object", }`, parseObject, erratic)
   437  	test(`{ "simple: bad object, }`, parseObject, erratic)
   438  	test(`{ "simple": "bad object",`, parseObject, erratic)
   439  	test(`{ "simple": "bad object" X`, parseObject, erratic)
   440  	test(`{ wrong: "object" }`, parseObject, erratic)
   441  
   442  	test(`	`, parseArray, erratic)
   443  	test(`	[	1,	"simple",    true,    "list"	]	`, parseArray, clean)
   444  	test(`[ 1, "simple", true, "list" ]`, parseArray, clean)
   445  	test(`  [ 1, "simple", true, "list" ], "tail"`, parseArray, taily)
   446  	test(`[ null, "simple", false, "list", ]`, parseArray, erratic)
   447  	test(`[ null, "simple", false, "list",,,0 ]`, parseArray, erratic)
   448  	test(`[ null, "simple", false, "list"`, parseArray, erratic)
   449  	test(`[ null,`, parseArray, erratic)
   450  	test(`[ null XXX`, parseArray, erratic)
   451  	test(`xxx`, parseArray, erratic)
   452  
   453  	test(`"simple\nstring"`, parseString, clean)
   454  	test(`"\nstring\twith\rescapes\u005c\u002Fyepp\backspace\formfeed"`, parseString, clean)
   455  	test(`	`, parseString, erratic)
   456  	test(`	"simple\nstring"	`, parseString, clean)
   457  	test(`	""	`, parseString, clean)
   458  	test(`	" 		 "  	`, parseString, clean)
   459  	test(`"simple\nstring", 123`, parseString, taily)
   460  	test(`"simple wrong string`, parseString, erratic)
   461  	test(`"simple wrong string\"`, parseString, erratic)
   462  	test(`simple wrong string\"`, parseString, erratic)
   463  
   464  	test(``, parseNumber, erratic)
   465  	test(`		`, parseNumber, erratic)
   466  	test(`123`, parseNumber, clean)
   467  	test(`	  123  	`, parseNumber, clean)
   468  	test(`0123`, parseNumber, clean)
   469  	test(`0123.03210`, parseNumber, clean)
   470  	test(`+0123.03210`, parseNumber, clean)
   471  	test(`-0123.03210`, parseNumber, clean)
   472  	test(`x123`, parseNumber, erratic)
   473  	test(`0x123`, parseNumber, taily)
   474  	test(`123x`, parseNumber, taily)
   475  	test(`123.321`, parseNumber, clean)
   476  	test(`+987`, parseNumber, clean)
   477  	test(`-321.`, parseNumber, clean)
   478  
   479  	test(`true`, parseBool, clean)
   480  	test(`	`, parseBool, erratic)
   481  	test(` xxxx	`, parseBool, erratic)
   482  	test(`false`, parseBool, clean)
   483  	test(`true,xxx`, parseBool, taily)
   484  	test(`trUe`, parseBool, erratic)
   485  
   486  	test(`null`, parseNull, clean)
   487  	test(`	`, parseNull, erratic)
   488  	test(`  xxx  `, parseNull, erratic)
   489  	test(`null,`, parseNull, taily)
   490  	test(`nUll`, parseNull, erratic)
   491  
   492  	test(`null`, ParseValue, clean)
   493  	test(`{ "not": [{ "so": "simple" }, "object"] }`, ParseValue, clean)
   494  	test(`[ 1, "simple", [ true, "list" ], null, -2.5 ]`, ParseValue, clean)
   495  	test(`"simple\nstring"`, ParseValue, clean)
   496  	test(`+0123.03210`, ParseValue, clean)
   497  	test(`false`, ParseValue, clean)
   498  	test(`  xxx  `, ParseValue, erratic)
   499  	test(`	false	`, ParseValue, clean)
   500  	test(`	`, ParseValue, erratic)
   501  }
   502  
   503  const source = `
   504  {
   505    "update": true,
   506    "time": 1576745142824,
   507    "uptime": 2749251.96,
   508    "hostname": "jet-one",
   509    "loadavg": {
   510      "kernel": {
   511        "runnable": 5,
   512        "total": 297
   513      },
   514      "last_pid": 6810,
   515      "average": [
   516        1.01,
   517        1.03,
   518        1.11
   519      ]
   520    },
   521    "mounts": [
   522      {
   523        "spec": "/dev/root",
   524        "file": "/",
   525        "vfstype": "ext4",
   526        "mntops": [
   527          "rw",
   528          "relatime",
   529          "data=ordered"
   530        ],
   531        "freq": 0,
   532        "passno": 0,
   533        "size": {
   534          "total_kb": 27736252,
   535          "used_kb": 13165476,
   536          "available_kb": 13138816
   537        }
   538      },
   539      {
   540        "file": "/dev",
   541        "vfstype": "devtmpfs",
   542        "mntops": [
   543          "rw",
   544          "relatime",
   545          "size=7976116k",
   546          "nr_inodes=1994029",
   547          "mode=755"
   548        ],
   549        "freq": 0,
   550        "passno": 0,
   551        "size": {
   552          "total_kb": 7976116,
   553          "used_kb": 0,
   554          "available_kb": 7976116
   555        },
   556        "spec": "devtmpfs"
   557      },
   558      {
   559        "vfstype": "sysfs",
   560        "mntops": [
   561          "rw",
   562          "nosuid",
   563          "nodev",
   564          "noexec",
   565          "relatime"
   566        ],
   567        "freq": 0,
   568        "passno": 0,
   569        "size": null,
   570        "spec": "sysfs",
   571        "file": "/sys"
   572      },
   573      {
   574        "size": null,
   575        "spec": "proc",
   576        "file": "/proc",
   577        "vfstype": "proc",
   578        "mntops": [
   579          "rw",
   580          "nosuid",
   581          "nodev",
   582          "noexec",
   583          "relatime"
   584        ],
   585        "freq": 0,
   586        "passno": 0
   587      },
   588      {
   589        "passno": 0,
   590        "size": {
   591          "used_kb": 4612,
   592          "available_kb": 8038300,
   593          "total_kb": 8042912
   594        },
   595        "spec": "tmpfs",
   596        "file": "/dev/shm",
   597        "vfstype": "tmpfs",
   598        "mntops": [
   599          "rw",
   600          "nosuid",
   601          "nodev"
   602        ],
   603        "freq": 0
   604      },
   605      {
   606        "spec": "devpts",
   607        "file": "/dev/pts",
   608        "vfstype": "devpts",
   609        "mntops": [
   610          "rw",
   611          "nosuid",
   612          "noexec",
   613          "relatime",
   614          "gid=5",
   615          "mode=620",
   616          "ptmxmode=000"
   617        ],
   618        "freq": 0,
   619        "passno": 0,
   620        "size": null
   621      },
   622      {
   623        "freq": 0,
   624        "passno": 0,
   625        "size": {
   626          "total_kb": 8042912,
   627          "used_kb": 833212,
   628          "available_kb": 7209700
   629        },
   630        "spec": "tmpfs",
   631        "file": "/run",
   632        "vfstype": "tmpfs",
   633        "mntops": [
   634          "rw",
   635          "nosuid",
   636          "nodev",
   637          "mode=755"
   638        ]
   639      },
   640      {
   641        "mntops": [
   642          "rw",
   643          "nosuid",
   644          "nodev",
   645          "noexec",
   646          "relatime",
   647          "size=5120k"
   648        ],
   649        "freq": 0,
   650        "passno": 0,
   651        "size": {
   652          "total_kb": 5120,
   653          "used_kb": 12,
   654          "available_kb": 5108
   655        },
   656        "spec": "tmpfs",
   657        "file": "/run/lock",
   658        "vfstype": "tmpfs"
   659      },
   660      {
   661        "vfstype": "tmpfs",
   662        "mntops": [
   663          "ro",
   664          "nosuid",
   665          "nodev",
   666          "noexec",
   667          "mode=755"
   668        ],
   669        "freq": 0,
   670        "passno": 0,
   671        "size": {
   672          "total_kb": 8042912,
   673          "used_kb": 0,
   674          "available_kb": 8042912
   675        },
   676        "spec": "tmpfs",
   677        "file": "/sys/fs/cgroup"
   678      },
   679      {
   680        "vfstype": "cgroup",
   681        "mntops": [
   682          "rw",
   683          "nosuid",
   684          "nodev",
   685          "noexec",
   686          "relatime",
   687          "xattr",
   688          "release_agent=/lib/systemd/systemd-cgroups-agent",
   689          "name=systemd"
   690        ],
   691        "freq": 0,
   692        "passno": 0,
   693        "size": null,
   694        "spec": "cgroup",
   695        "file": "/sys/fs/cgroup/systemd"
   696      },
   697      {
   698        "freq": 0,
   699        "passno": 0,
   700        "size": null,
   701        "spec": "pstore",
   702        "file": "/sys/fs/pstore",
   703        "vfstype": "pstore",
   704        "mntops": [
   705          "rw",
   706          "nosuid",
   707          "nodev",
   708          "noexec",
   709          "relatime"
   710        ]
   711      },
   712      {
   713        "passno": 0,
   714        "size": null,
   715        "spec": "cgroup",
   716        "file": "/sys/fs/cgroup/cpu,cpuacct",
   717        "vfstype": "cgroup",
   718        "mntops": [
   719          "rw",
   720          "nosuid",
   721          "nodev",
   722          "noexec",
   723          "relatime",
   724          "cpu",
   725          "cpuacct"
   726        ],
   727        "freq": 0
   728      },
   729      {
   730        "mntops": [
   731          "rw",
   732          "nosuid",
   733          "nodev",
   734          "noexec",
   735          "relatime",
   736          "freezer"
   737        ],
   738        "freq": 0,
   739        "passno": 0,
   740        "size": null,
   741        "spec": "cgroup",
   742        "file": "/sys/fs/cgroup/freezer",
   743        "vfstype": "cgroup"
   744      },
   745      {
   746        "passno": 0,
   747        "size": null,
   748        "spec": "cgroup",
   749        "file": "/sys/fs/cgroup/perf_event",
   750        "vfstype": "cgroup",
   751        "mntops": [
   752          "rw",
   753          "nosuid",
   754          "nodev",
   755          "noexec",
   756          "relatime",
   757          "perf_event"
   758        ],
   759        "freq": 0
   760      },
   761      {
   762        "mntops": [
   763          "rw",
   764          "nosuid",
   765          "nodev",
   766          "noexec",
   767          "relatime",
   768          "debug"
   769        ],
   770        "freq": 0,
   771        "passno": 0,
   772        "size": null,
   773        "spec": "cgroup",
   774        "file": "/sys/fs/cgroup/debug",
   775        "vfstype": "cgroup"
   776      },
   777      {
   778        "vfstype": "cgroup",
   779        "mntops": [
   780          "rw",
   781          "nosuid",
   782          "nodev",
   783          "noexec",
   784          "relatime",
   785          "memory"
   786        ],
   787        "freq": 0,
   788        "passno": 0,
   789        "size": null,
   790        "spec": "cgroup",
   791        "file": "/sys/fs/cgroup/memory"
   792      },
   793      {
   794        "size": null,
   795        "spec": "cgroup",
   796        "file": "/sys/fs/cgroup/pids",
   797        "vfstype": "cgroup",
   798        "mntops": [
   799          "rw",
   800          "nosuid",
   801          "nodev",
   802          "noexec",
   803          "relatime",
   804          "pids"
   805        ],
   806        "freq": 0,
   807        "passno": 0
   808      },
   809      {
   810        "spec": "cgroup",
   811        "file": "/sys/fs/cgroup/net_cls,net_prio",
   812        "vfstype": "cgroup",
   813        "mntops": [
   814          "rw",
   815          "nosuid",
   816          "nodev",
   817          "noexec",
   818          "relatime",
   819          "net_cls",
   820          "net_prio"
   821        ],
   822        "freq": 0,
   823        "passno": 0,
   824        "size": null
   825      },
   826      {
   827        "size": null,
   828        "spec": "cgroup",
   829        "file": "/sys/fs/cgroup/cpuset",
   830        "vfstype": "cgroup",
   831        "mntops": [
   832          "rw",
   833          "nosuid",
   834          "nodev",
   835          "noexec",
   836          "relatime",
   837          "cpuset"
   838        ],
   839        "freq": 0,
   840        "passno": 0
   841      },
   842      {
   843        "spec": "cgroup",
   844        "file": "/sys/fs/cgroup/blkio",
   845        "vfstype": "cgroup",
   846        "mntops": [
   847          "rw",
   848          "nosuid",
   849          "nodev",
   850          "noexec",
   851          "relatime",
   852          "blkio"
   853        ],
   854        "freq": 0,
   855        "passno": 0,
   856        "size": null
   857      },
   858      {
   859        "size": null,
   860        "spec": "cgroup",
   861        "file": "/sys/fs/cgroup/devices",
   862        "vfstype": "cgroup",
   863        "mntops": [
   864          "rw",
   865          "nosuid",
   866          "nodev",
   867          "noexec",
   868          "relatime",
   869          "devices"
   870        ],
   871        "freq": 0,
   872        "passno": 0
   873      },
   874      {
   875        "vfstype": "debugfs",
   876        "mntops": [
   877          "rw",
   878          "relatime"
   879        ],
   880        "freq": 0,
   881        "passno": 0,
   882        "size": null,
   883        "spec": "debugfs",
   884        "file": "/sys/kernel/debug"
   885      },
   886      {
   887        "vfstype": "mqueue",
   888        "mntops": [
   889          "rw",
   890          "relatime"
   891        ],
   892        "freq": 0,
   893        "passno": 0,
   894        "size": null,
   895        "spec": "mqueue",
   896        "file": "/dev/mqueue"
   897      },
   898      {
   899        "spec": "configfs",
   900        "file": "/sys/kernel/config",
   901        "vfstype": "configfs",
   902        "mntops": [
   903          "rw",
   904          "relatime"
   905        ],
   906        "freq": 0,
   907        "passno": 0,
   908        "size": null
   909      },
   910      {
   911        "vfstype": "tmpfs",
   912        "mntops": [
   913          "rw",
   914          "nosuid",
   915          "nodev",
   916          "relatime",
   917          "size=804292k",
   918          "mode=700",
   919          "uid=1001",
   920          "gid=1001"
   921        ],
   922        "freq": 0,
   923        "passno": 0,
   924        "size": {
   925          "total_kb": 804292,
   926          "used_kb": 16,
   927          "available_kb": 804276
   928        },
   929        "spec": "tmpfs",
   930        "file": "/run/user/1001"
   931      },
   932      {
   933        "freq": 0,
   934        "passno": 0,
   935        "size": {
   936          "total_kb": 804292,
   937          "used_kb": 0,
   938          "available_kb": 804292
   939        },
   940        "spec": "tmpfs",
   941        "file": "/run/user/1002",
   942        "vfstype": "tmpfs",
   943        "mntops": [
   944          "rw",
   945          "nosuid",
   946          "nodev",
   947          "relatime",
   948          "size=804292k",
   949          "mode=700",
   950          "uid=1002",
   951          "gid=1002"
   952        ]
   953      }
   954    ],
   955    "meminfo": {
   956      "MemFree_kB": 3776048,
   957      "MemAvailable_kB": 5085380,
   958      "Buffers_kB": 199708,
   959      "Cached_kB": 1904324,
   960      "SwapCached_kB": 0,
   961      "SwapTotal_kB": 0,
   962      "SwapFree_kB": 0,
   963      "MemTotal_kB": 8042912
   964    },
   965    "spools": [
   966      {
   967        "path": "/var/cache/jetson",
   968        "exists": true,
   969        "count": 0
   970      }
   971    ],
   972    "sensors": [
   973      {
   974        "adapter": "Virtual device",
   975        "values": [
   976          {
   977            "crit": 101,
   978            "name": "temp1",
   979            "input": 20.5
   980          }
   981        ],
   982        "sensor": "BCPU-therm-virtual-0"
   983      },
   984      {
   985        "adapter": "Virtual device",
   986        "values": [
   987          {
   988            "name": "temp1",
   989            "input": 20.5,
   990            "crit": 101
   991          }
   992        ],
   993        "sensor": "MCPU-therm-virtual-0"
   994      },
   995      {
   996        "sensor": "GPU-therm-virtual-0",
   997        "adapter": "Virtual device",
   998        "values": [
   999          {
  1000            "crit": -40,
  1001            "name": "temp1",
  1002            "input": 19
  1003          }
  1004        ]
  1005      },
  1006      {
  1007        "sensor": "Tboard_tegra-virtual-0",
  1008        "adapter": "Virtual device",
  1009        "values": [
  1010          {
  1011            "name": "temp1",
  1012            "input": 18,
  1013            "crit": 107
  1014          }
  1015        ]
  1016      },
  1017      {
  1018        "sensor": "Tdiode_tegra-virtual-0",
  1019        "adapter": "Virtual device",
  1020        "values": [
  1021          {
  1022            "name": "temp1",
  1023            "input": 17.75,
  1024            "crit": 107
  1025          }
  1026        ]
  1027      },
  1028      {
  1029        "sensor": "thermal-fan-est-virtual-0",
  1030        "adapter": "Virtual device",
  1031        "values": [
  1032          {
  1033            "name": "temp1",
  1034            "input": 19.6
  1035          }
  1036        ]
  1037      }
  1038    ],
  1039    "net": [
  1040      {
  1041        "response": {
  1042          "status": 200,
  1043          "content_type": "text/plain; charset=utf-8",
  1044          "body": "31.173.81.31"
  1045        },
  1046        "url": "https://ifconfig.co/",
  1047        "scheme": "https",
  1048        "error": null
  1049      }
  1050    ]
  1051  }
  1052  `
  1053  
  1054  func TestAll(t *testing.T) {
  1055  	json, tail, err := ParseValue(source)
  1056  	if err != nil {
  1057  		t.Errorf("GetValue(%+q): %v", source, err)
  1058  	}
  1059  	if tail != "" {
  1060  		t.Errorf("%+q tail", tail)
  1061  	}
  1062  	t.Logf("%s", json.Json())
  1063  }