Skip to content

Commit

Permalink
Merge pull request #72 from miracl/separate-schema
Browse files Browse the repository at this point in the history
Separate Schema from Conflate
  • Loading branch information
andy-miracl authored Jul 26, 2018
2 parents 2eb4049 + e8c9911 commit e5fb9a1
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 158 deletions.
55 changes: 4 additions & 51 deletions conflate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ var Includes = "includes"
// Conflate contains a 'working' merged data set and optionally a JSON v4 schema
type Conflate struct {
data interface{}
schema interface{}
loader loader
}

Expand Down Expand Up @@ -108,55 +107,14 @@ func (c *Conflate) AddData(data ...[]byte) error {
return c.addData(fdata...)
}

// SetSchemaFile loads a JSON v4 schema from the given path
func (c *Conflate) SetSchemaFile(path string) error {
url, err := toURL(nil, path)
if err != nil {
return wrapError(err, "Failed to obtain url to schema file")
}
return c.SetSchemaURL(url)
}

// SetSchemaURL loads a JSON v4 schema from the given URL
func (c *Conflate) SetSchemaURL(url url.URL) error {
data, err := loadURL(url)
if err != nil {
return wrapError(err, "Failed to load schema file")
}
return c.SetSchemaData(data)
}

// SetSchemaData loads a JSON v4 schema from the given data
func (c *Conflate) SetSchemaData(data []byte) error {
var schema interface{}
err := JSONUnmarshal(data, &schema)
if err != nil {
return wrapError(err, "Schema is not valid json")
}
err = validateSchema(schema)
if err != nil {
return wrapError(err, "The schema is not valid against the meta-schema http://json-schema.org/draft-04/schema")
}
c.schema = schema
return nil
}

// ApplyDefaults sets any nil or missing values in the data, to the default values defined in the JSON v4 schema
func (c *Conflate) ApplyDefaults() error {
if c.schema == nil {
return makeError("Schema is not set")
}
err := applyDefaults(&c.data, c.schema)
return wrapError(err, "The defaults could not be applied")
func (c *Conflate) ApplyDefaults(s *Schema) error {
return s.ApplyDefaults(&c.data)
}

// Validate checks the data against the JSON v4 schema
func (c *Conflate) Validate() error {
if c.schema == nil {
return makeError("Schema is not set")
}
err := validate(&c.data, c.schema)
return wrapError(err, "Schema validation failed")
func (c *Conflate) Validate(s *Schema) error {
return s.Validate(c.data)
}

// Unmarshal extracts the data as a Golang object
Expand All @@ -179,11 +137,6 @@ func (c *Conflate) MarshalTOML() ([]byte, error) {
return tomlMarshal(c.data)
}

// MarshalSchema exports the schema as JSON
func (c *Conflate) MarshalSchema() ([]byte, error) {
return jsonMarshal(c.schema)
}

func (c *Conflate) addData(fdata ...filedata) error {
fdata, err := c.loader.loadDataRecursive(nil, fdata...)
if err != nil {
Expand Down
12 changes: 7 additions & 5 deletions conflate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func main() {

var data dataFlag
flag.Var(&data, "data", "The path/url of JSON/YAML/TOML data, or 'stdin' to read from standard input")
schema := flag.String("schema", "", "The path/url of a JSON v4 schema file")
schemaFile := flag.String("schema", "", "The path/url of a JSON v4 schema file")
defaults := flag.Bool("defaults", false, "Apply defaults from schema to data")
validate := flag.Bool("validate", false, "Validate the data against the schema")
format := flag.String("format", "", "Output format of the data JSON/YAML/TOML")
Expand Down Expand Up @@ -62,16 +62,18 @@ func main() {
}
}

if *schema != "" {
err := c.SetSchemaFile(*schema)
var schema *conflate.Schema
if *schemaFile != "" {
s, err := conflate.NewSchemaFile(*schemaFile)
failIfError(err)
schema = s
}
if *defaults {
err := c.ApplyDefaults()
err := c.ApplyDefaults(schema)
failIfError(err)
}
if *validate {
err := c.Validate()
err := c.Validate(schema)
failIfError(err)
}
if *format != "" {
Expand Down
87 changes: 12 additions & 75 deletions conflate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,87 +171,48 @@ func TestFromFiles_ExpandError(t *testing.T) {
assert.Contains(t, err.Error(), "Failed to load url")
}

func TestFromFiles_SchemaBadUrl(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile(`!"£$%^&*()`)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Failed to obtain url to schema file")
}

func TestFromFiles_SchemaMissingError(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("missing file")
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Failed to load schema file")
}

func TestFromFiles_SchemaBadJsonError(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("conflate.go")
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Schema is not valid json")
}

func TestFromFiles_SchemaBadSchemaError(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/bad.schema.json")
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "The schema is not valid against the meta-schema")
}

func TestFromFiles_Schema(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/test.schema.json")
assert.Nil(t, err)
}

func TestFromFiles_ValidationNoSchemaErro(t *testing.T) {
func TestFromFiles_ValidationNoSchemaError(t *testing.T) {
c, err := FromFiles("testdata/valid_child.json")
assert.Nil(t, err)
err = c.Validate()
err = c.Validate(nil)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Schema is not set")
}

func TestFromFiles_ValidationError(t *testing.T) {
c, err := FromFiles("testdata/valid_child.json")
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/test.schema.json")
s, err := NewSchemaFile("testdata/test.schema.json")
assert.Nil(t, err)
err = c.Validate()
err = c.Validate(s)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Schema validation failed")
}

func TestFromFiles_ValidationOk(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/test.schema.json")
s, err := NewSchemaFile("testdata/test.schema.json")
assert.Nil(t, err)
err = c.Validate()
err = c.Validate(s)
assert.Nil(t, err)
}

func TestFromFiles_ApplyDefaultsNoSchema(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.ApplyDefaults()
err = c.ApplyDefaults(nil)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "Schema is not set")
}

func TestFromFiles_ApplyDefaultsError(t *testing.T) {
c, err := FromFiles("testdata/valid_parent.json")
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/test.schema.json")
s, err := NewSchemaFile("testdata/test.schema.json")
assert.Nil(t, err)
c.schema = []interface{}{"not a map"}
err = c.ApplyDefaults()
s.s = []interface{}{"not a map"}
err = c.ApplyDefaults(s)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "The defaults could not be applied")
assert.Contains(t, err.Error(), "Schema section is not a map")
Expand All @@ -260,9 +221,9 @@ func TestFromFiles_ApplyDefaultsError(t *testing.T) {
func TestFromFiles_ApplyDefaults(t *testing.T) {
c, err := FromFiles()
assert.Nil(t, err)
err = c.SetSchemaFile("testdata/test.schema.json")
s, err := NewSchemaFile("testdata/test.schema.json")
assert.Nil(t, err)
err = c.ApplyDefaults()
err = c.ApplyDefaults(s)
assert.Nil(t, err)
testData := TestData{}
err = c.Unmarshal(&testData)
Expand Down Expand Up @@ -344,30 +305,6 @@ func TestConflate_MarshalTOML(t *testing.T) {
assert.Equal(t, testMarshalTOML, data)
}

func TestConflate_MarshalSchema(t *testing.T) {
c := New()
err := c.SetSchemaData([]byte("{}"))
assert.Nil(t, err)
data, err := c.MarshalSchema()
assert.Nil(t, err)
assert.Equal(t, "{}\n", string(data))
}

func TestConflate_MarshalSchemaNil(t *testing.T) {
c := New()
data, err := c.MarshalSchema()
assert.Nil(t, err)
assert.Equal(t, string(data), "null\n")
}

func TestConflate_MarshalSchemaError(t *testing.T) {
c := New()
c.schema = make(chan int, 1)
_, err := c.MarshalSchema()
assert.NotNil(t, err)
assert.Contains(t, err.Error(), "The data could not be marshalled")
}

func TestConflate_addDataError(t *testing.T) {
c := New()
err := c.AddData([]byte(`{"includes": ["missing"]}`))
Expand Down
6 changes: 3 additions & 3 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ func main() {
return
}
// load a json schema
err = c.SetSchemaFile(path.Join(thisDir, "../testdata/test.schema.json"))
schema, err := conflate.NewSchemaFile(path.Join(thisDir, "../testdata/test.schema.json"))
if err != nil {
fmt.Println(err)
return
}
// apply defaults defined in schema to merged data
err = c.ApplyDefaults()
err = c.ApplyDefaults(schema)
if err != nil {
fmt.Println(err)
return
}
// validate merged data against schema
err = c.Validate()
err = c.Validate(schema)
if err != nil {
fmt.Println(err)
return
Expand Down
23 changes: 23 additions & 0 deletions filedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,26 @@ func expand(b []byte) ([]byte, int) {
return "$" + name
})), c
}

var getSchema = getDefaultSchema

func getDefaultSchema() map[string]interface{} {
return map[string]interface{}{
"anyOf": []interface{}{
map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
Includes: map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"type": "string",
},
},
},
},
map[string]interface{}{
"type": "null",
},
},
}
}
Loading

0 comments on commit e5fb9a1

Please sign in to comment.