Skip to content

Commit

Permalink
feat: add github.com/tailscale/hujson extensions (#1294)
Browse files Browse the repository at this point in the history
The hujson is a JSON package from tailscale allowing JSON files to
contain comments that is also more liberal with respect to commas.

We want to slowly upgrade all user-facing JSON-parsing code to use this
more relaxed standard for parsing JSONs, because that would make our
user's life significantly simpler in terms of writing and updating those
files.

In the short term, I would like the configuration file driving the usage
of beacons to use this relaxed parsing.

To this end, I am adding handy wrappers that combine using hujson with
using the standard library parser to have a single hujson aware parsing
function that behaves like the standard library's json.Unmarshal.

Part of ooni/probe#2531
  • Loading branch information
bassosimone authored Sep 22, 2023
1 parent e27eead commit a0f51b7
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
18 changes: 18 additions & 0 deletions internal/hujsonx/hujsonx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Package hujsonx contains github.com/tailscale/hujson extensions.
package hujsonx

import (
"encoding/json"

"github.com/tailscale/hujson"
)

// Unmarshal is like [json.Unmarshal] except that it first removes comments and
// extra commas using the [hujson.Standardize] function.
func Unmarshal(data []byte, v any) error {
data, err := hujson.Standardize(data)
if err != nil {
return err
}
return json.Unmarshal(data, v)
}
33 changes: 33 additions & 0 deletions internal/hujsonx/hujsonx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package hujsonx

import (
"errors"
"io"
"testing"
)

type user struct {
Name string
Age int
}

func TestHuJSONXWorkingAsIntended(t *testing.T) {
t.Run("for invalid input", func(t *testing.T) {
input := []byte("{")
var v user
err := Unmarshal(input, &v)
if !errors.Is(err, io.ErrUnexpectedEOF) {
t.Fatal("unexpected error", err)
}
})

t.Run("for valid JSON we cannot map to a real struct", func(t *testing.T) {
input := []byte(`{"Name": {}, "Age": []}`)
var v user
err := Unmarshal(input, &v)
expected := "json: cannot unmarshal object into Go struct field user.Name of type string"
if err == nil || err.Error() != expected {
t.Fatal("unexpected error", err)
}
})
}

0 comments on commit a0f51b7

Please sign in to comment.