github.com/icyphox/x@v0.0.355-0.20220311094250-029bd783e8b8/jsonschemax/keys_test.go (about)

     1  package jsonschemax
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"testing"
    10  
    11  	"github.com/ory/x/snapshotx"
    12  
    13  	"github.com/pkg/errors"
    14  
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/ory/jsonschema/v3"
    18  )
    19  
    20  const recursiveSchema = `{
    21    "$schema": "http://json-schema.org/draft-07/schema#",
    22    "$id": "test.json",
    23    "definitions": {
    24      "foo": {
    25        "type": "object",
    26        "properties": {
    27  		"bars": {
    28  			"type": "string",
    29  			"format": "email",
    30  			"pattern": ".*"
    31  		},
    32          "bar": {
    33            "$ref": "#/definitions/bar"
    34          }
    35        },
    36        "required":["bars"]
    37      },
    38      "bar": {
    39        "type": "object",
    40        "properties": {
    41  		"foos": {
    42  		  "type": "string",
    43  		  "minLength": 1,
    44  		  "maxLength": 10
    45  		},
    46          "foo": {
    47            "$ref": "#/definitions/foo"
    48          }
    49        }
    50      }
    51    },
    52    "type": "object",
    53    "properties": {
    54      "bar": {
    55        "$ref": "#/definitions/bar"
    56      }
    57    }
    58  }`
    59  
    60  func readFile(t *testing.T, path string) string {
    61  	schema, err := ioutil.ReadFile(path)
    62  	require.NoError(t, err)
    63  	return string(schema)
    64  }
    65  
    66  const fooExtensionName = "fooExtension"
    67  
    68  type (
    69  	extensionConfig struct {
    70  		NotAJSONSchemaKey string `json:"not-a-json-schema-key"`
    71  	}
    72  )
    73  
    74  func fooExtensionCompile(_ jsonschema.CompilerContext, m map[string]interface{}) (interface{}, error) {
    75  	if raw, ok := m[fooExtensionName]; ok {
    76  		var b bytes.Buffer
    77  		if err := json.NewEncoder(&b).Encode(raw); err != nil {
    78  			return nil, errors.WithStack(err)
    79  		}
    80  
    81  		var e extensionConfig
    82  		if err := json.NewDecoder(&b).Decode(&e); err != nil {
    83  			return nil, errors.WithStack(err)
    84  		}
    85  
    86  		return &e, nil
    87  	}
    88  	return nil, nil
    89  }
    90  
    91  func fooExtensionValidate(_ jsonschema.ValidationContext, _, _ interface{}) error {
    92  	return nil
    93  }
    94  
    95  func (ec *extensionConfig) EnhancePath(p Path) map[string]interface{} {
    96  	if ec.NotAJSONSchemaKey != "" {
    97  		fmt.Printf("enhancing path: %s with custom property %s\n", p.Name, ec.NotAJSONSchemaKey)
    98  		return map[string]interface{}{
    99  			ec.NotAJSONSchemaKey: p.Name,
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  func TestListPathsWithRecursion(t *testing.T) {
   106  	for k, tc := range []struct {
   107  		recursion uint8
   108  		expected  interface{}
   109  	}{
   110  		{
   111  			recursion: 5,
   112  		},
   113  	} {
   114  		t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
   115  			c := jsonschema.NewCompiler()
   116  			require.NoError(t, c.AddResource("test.json", bytes.NewBufferString(recursiveSchema)))
   117  			actual, err := ListPathsWithRecursion(context.Background(), "test.json", c, tc.recursion)
   118  			require.NoError(t, err)
   119  
   120  			snapshotx.SnapshotTExcept(t, actual, nil)
   121  		})
   122  	}
   123  }
   124  
   125  func TestListPaths(t *testing.T) {
   126  	for k, tc := range []struct {
   127  		schema    string
   128  		expectErr bool
   129  		extension *jsonschema.Extension
   130  	}{
   131  		{
   132  			schema: readFile(t, "./stub/.oathkeeper.schema.json"),
   133  		},
   134  		{
   135  			schema: readFile(t, "./stub/nested-simple-array.schema.json"),
   136  		},
   137  		{
   138  			schema: readFile(t, "./stub/config.schema.json"),
   139  		},
   140  		{
   141  			schema: readFile(t, "./stub/nested-array.schema.json"),
   142  		},
   143  		{
   144  			// this should fail because of recursion
   145  			schema:    recursiveSchema,
   146  			expectErr: true,
   147  		},
   148  		{
   149  			schema: `{
   150    "$schema": "http://json-schema.org/draft-07/schema#",
   151    "$id": "test.json",
   152    "oneOf": [
   153      {
   154        "type": "object",
   155        "properties": {
   156          "list": {
   157            "type": "array",
   158            "items": {
   159              "type": "string"
   160            }
   161          },
   162          "foo": {
   163            "default": false,
   164            "type": "boolean"
   165          },
   166          "bar": {
   167            "type": "boolean",
   168            "default": "asdf",
   169            "readOnly": true
   170          }
   171        }
   172      },
   173      {
   174        "type": "object",
   175        "properties": {
   176          "foo": {
   177            "type": "boolean"
   178          }
   179        }
   180      }
   181    ]
   182  }`,
   183  		},
   184  		{
   185  			schema: `{
   186    "$schema": "http://json-schema.org/draft-07/schema#",
   187    "$id": "test.json",
   188    "type": "object",
   189    "required": ["foo"],
   190    "properties": {
   191      "foo": {
   192        "type": "boolean"
   193      },
   194      "bar": {
   195        "type": "string",
   196        "fooExtension": {
   197          "not-a-json-schema-key": "foobar"
   198        }
   199      }
   200    }
   201  }`,
   202  			extension: &jsonschema.Extension{
   203  				Meta:     nil,
   204  				Compile:  fooExtensionCompile,
   205  				Validate: fooExtensionValidate,
   206  			},
   207  		},
   208  		{
   209  			schema: `{
   210    "$schema": "http://json-schema.org/draft-07/schema#",
   211    "$id": "test.json",
   212    "type": "object",
   213    "definitions": {
   214      "foo": {
   215        "type": "string"
   216      }
   217    },
   218    "properties": {
   219      "bar": {
   220        "type": "array",
   221        "items": {
   222          "$ref": "#/definitions/foo"
   223        }
   224      }
   225    }
   226  }`,
   227  		},
   228  		{
   229  			schema: `{
   230    "$schema": "http://json-schema.org/draft-07/schema#",
   231    "$id": "test.json",
   232    "type": "object",
   233    "definitions": {
   234      "foo": {
   235        "type": "string"
   236      },
   237      "bar": {
   238        "type": "array",
   239        "items": {
   240          "$ref": "#/definitions/foo"
   241        },
   242        "required": ["foo"]
   243      }
   244    },
   245    "properties": {
   246      "baz": {
   247        "type": "array",
   248        "items": {
   249          "$ref": "#/definitions/bar"
   250        }
   251      }
   252    }
   253  }`,
   254  		},
   255  		{
   256  			schema: `{
   257    "$schema": "http://json-schema.org/draft-07/schema#",
   258    "$id": "test.json",
   259    "type": "object",
   260    "definitions": {
   261      "foo": {
   262        "type": "string"
   263      },
   264      "bar": {
   265        "type": "object",
   266        "properties": {
   267          "foo": {
   268            "$ref": "#/definitions/foo"
   269          }
   270        },
   271        "required": ["foo"]
   272      }
   273    },
   274    "properties": {
   275      "baz": {
   276        "type": "array",
   277        "items": {
   278          "$ref": "#/definitions/bar"
   279        }
   280      }
   281    }
   282  }`,
   283  		},
   284  	} {
   285  		t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
   286  			c := jsonschema.NewCompiler()
   287  			if tc.extension != nil {
   288  				c.Extensions[fooExtensionName] = *tc.extension
   289  			}
   290  
   291  			require.NoError(t, c.AddResource("test.json", bytes.NewBufferString(tc.schema)))
   292  			actual, err := ListPathsWithArraysIncluded(context.Background(), "test.json", c)
   293  			if tc.expectErr {
   294  				require.Error(t, err, "%+v", actual)
   295  				return
   296  			}
   297  			require.NoError(t, err)
   298  
   299  			snapshotx.SnapshotTExcept(t, actual, nil)
   300  		})
   301  	}
   302  }