WblSchema

WblSchema — JSON schema parsing and representation

Stability Level

Unstable, unless otherwise indicated

Functions

Types and Values

Object Hierarchy

    GBoxed
    ├── WblGeneratedInstance
    ╰── WblSchemaNode
    GObject
    ╰── WblSchema

Includes

#include <libwalbottle/wbl-schema.h>

Description

WblSchema represents a single JSON schema, at the top level. This is a tree of WblSchemaNodes, with one guaranteed to exist at the top level (retrievable using wbl_schema_get_root()) and others lower down representing sub-schemas.

When loading a schema, it is validated for well-formedness and adherence to the JSON meta-schema (which defines the format used for schemas). Invalid schemas will fail to load.

Two main operations may be performed on a loaded schema: application of the schema to a JSON instance, and generation of instances from the schema. Applying a schema to an instance validates that instance against the schema, returning success or a validation error. Generating instances from a schema produces zero or more JSON instances which test various boundary conditions of the schema. They are designed to be used in testing parser implementations for that schema.

Build system integration

The most common usage of Walbottle is to integrate it into the unit tests for a parser in the software under test (SUT). This is typically done with the json-schema-generate utility which comes with Walbottle.

To do so is straightforward if the SUT is using autotools. Add the following to the configure.ac file in the SUT:

1
2
3
4
5
6
7
AC_PATH_PROG([JSON_SCHEMA_VALIDATE],[json-schema-validate])
AC_PATH_PROG([JSON_SCHEMA_GENERATE],[json-schema-generate])

AS_IF([test "$JSON_SCHEMA_VALIDATE" == ""],
      [AC_MSG_ERROR([json-schema-validate not found])])
AS_IF([test "$JSON_SCHEMA_GENERATE" == ""],
      [AC_MSG_ERROR([json-schema-generate not found])])

Then add the following in the Makefile.am for the SUT’s parser unit tests and adjust json_schemas to point to the schemas for the format (or formats) accepted by the SUT’s parser:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
json_schemas = \
    my-format.schema.json \
    my-other-format.schema.json \
    $(NULL)

EXTRA_DIST += $(json_schemas)

check-json-schema: $(json_schemas)
    $(AM_V_GEN)$(JSON_SCHEMA_VALIDATE) $^
check-local: check-json-schema
.PHONY: check-json-schema

json_schemas_c = $(json_schemas:.schema.json=.schema.c)

CLEANFILES += $(json_schemas_c)

%.schema.c: %.schema.json
    $(AM_V_GEN)$(JSON_SCHEMA_GENERATE) \
        --c-variable-name=$(subst -,_,$(notdir $*))_json_instances \
        --format c $^ > $@

If using the GLib test framework, a typical way of then using the generated test vectors in a test suite is to include the generated C file and add a unit test for each vector. In Makefile.am:

1
my_test_suite_SOURCES = my-test-suite.c my-format.schema.c

And in the test suite code itself (my-test-suite.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "my-format.schema.c"



// Test the parser with each generated test vector from the JSON schema.
static void
test_parser_generated (gconstpointer user_data)
{
  guint i;
  GObject *parsed = NULL;
  GError *error = NULL;

  i = GPOINTER_TO_UINT (user_data);

  parsed = try_parsing_string (my_format_json_instances[i].json,
                               my_format_json_instances[i].size, &error);

  if (my_format_json_instances[i].is_valid)
    {
      // Assert @parsed is valid.
      g_assert_no_error (error);
      g_assert (G_IS_OBJECT (parser));
    }
  else
    {
      // Assert parsing failed.
      g_assert_error (error, SOME_ERROR_DOMAIN, SOME_ERROR_CODE);
      g_assert (parsed == NULL);
    }

  g_clear_error (&error);
  g_clear_object (&parsed);
}



int
main (int argc, char *argv[])
{
  guint i;



  for (i = 0; i < G_N_ELEMENTS (my_format_json_instances); i++)
    {
      gchar *test_name = NULL;

      test_name = g_strdup_printf ("/parser/generated/%u", i);
      g_test_add_data_func (test_name, GUINT_TO_POINTER (i),
                            test_parser_generated);
      g_free (test_name);
    }


}

Functions

wbl_schema_new ()

WblSchema *
wbl_schema_new (void);

Creates a new WblSchema with default properties.

Returns

a new WblSchema; unref with g_object_unref().

[transfer full]

Since: 0.1.0


wbl_schema_load_from_data ()

void
wbl_schema_load_from_data (WblSchema *self,
                           const gchar *data,
                           gssize length,
                           GError **error);

Load and parse a JSON schema from the given serialised JSON data .

See wbl_schema_load_from_stream_async() for more details.

Parameters

self

a WblSchema

 

data

serialised JSON data to load.

[array length=length]

length

length of data , or -1 if data is nul-terminated

 

error

return location for a GError, or NULL

 

Since: 0.1.0


wbl_schema_load_from_file ()

void
wbl_schema_load_from_file (WblSchema *self,
                           const gchar *filename,
                           GError **error);

Load and parse a JSON schema from the given local file containing serialised JSON data. To load a non-local file, or to use a URI, use wbl_schema_load_from_stream_async().

See wbl_schema_load_from_stream_async() for more details.

Parameters

self

a WblSchema

 

filename

path to a local JSON file to load.

[type filename]

error

return location for a GError, or NULL

 

Since: 0.1.0


wbl_schema_load_from_stream ()

void
wbl_schema_load_from_stream (WblSchema *self,
                             GInputStream *stream,
                             GCancellable *cancellable,
                             GError **error);

Load and parse a JSON schema from an input stream providing serialised JSON data. This is the synchronous version of wbl_schema_load_from_stream_async(), which is preferred for production code.

See wbl_schema_load_from_stream_async() for more details.

Parameters

self

a WblSchema

 

stream

stream of serialised JSON data to load

 

cancellable

a GCancellable, or NULL.

[nullable]

error

return location for a GError, or NULL

 

Since: 0.1.0


wbl_schema_load_from_stream_async ()

void
wbl_schema_load_from_stream_async (WblSchema *self,
                                   GInputStream *stream,
                                   GCancellable *cancellable,
                                   GAsyncReadyCallback callback,
                                   gpointer user_data);

Load and parse a JSON schema from an input stream providing serialised JSON data. The loading and parsing is done asynchronously and, once complete, callback is invoked in the main context which was thread default at the time of calling this method.

Call wbl_schema_load_from_stream_finish() from callback to retrieve information about any parsing errors.

If a schema is loaded successfully, it is guaranteed to be valid.

Any previously loaded schemas will be unloaded when starting to load a new one, even if the new load operation fails (e.g. due to the new schema being invalid).

This is the preferred method for loading a schema due to the potential blocking involved in the I/O.

Parameters

self

a WblSchema

 

stream

stream of serialised JSON data to load

 

cancellable

a GCancellable, or NULL.

[nullable]

callback

callback to invoke when parsing is complete, or NULL.

[scope async][nullable]

user_data

user data to pass to callback .

[closure callback]

Since: 0.1.0


wbl_schema_load_from_stream_finish ()

void
wbl_schema_load_from_stream_finish (WblSchema *self,
                                    GAsyncResult *result,
                                    GError **error);

Finish an asynchronous schema loading operation started with wbl_schema_load_from_stream_async().

Parameters

self

a WblSchema

 

result

result from the asynchronous operation

 

error

return location for a GError, or NULL

 

Since: 0.1.0


wbl_schema_get_root ()

WblSchemaNode *
wbl_schema_get_root (WblSchema *self);

Get the root schema from the parsed schema document. If no document has been parsed using wbl_schema_load_from_stream_async() yet, or if the parsed document was invalid, NULL is returned.

The returned object is valid as long as the WblSchema is alive and has not started parsing another document.

Parameters

self

a WblSchema

 

Returns

a JSON schema root object, or NULL.

[transfer none][nullable]

Since: 0.1.0


wbl_schema_apply ()

void
wbl_schema_apply (WblSchema *self,
                  JsonNode *instance,
                  GError **error);

Apply a JSON Schema to a JSON instance, validating whether the instance conforms to the schema. The instance may be any kind of JSON node, and does not necessarily have to be a JSON object.

Parameters

self

a WblSchema

 

instance

the JSON instance to validate against the schema

 

error

return location for a GError, or NULL

 

Since: 0.1.0


wbl_schema_generate_instances ()

GPtrArray *
wbl_schema_generate_instances (WblSchema *self,
                               WblGenerateInstanceFlags flags);

Generate JSON instances for the given JSON Schema. These instances are designed to be used as test vectors for code which parses and handles JSON following this schema. By default, instances which are both valid and invalid are generated, with the invalid schemas designed to test boundary conditions of validity, and common parsing problems.

All generated instances are correctly formed JSON, and all will parse successfully. By design, however, some of the instances will not validate according to the given WblSchema.

Parameters

self

a WblSchema

 

flags

flags affecting how instances are generated

 

Returns

newly allocated array of WblGeneratedInstances.

[transfer full][element-type WblGeneratedInstance]

Since: 0.1.0


wbl_schema_node_ref ()

WblSchemaNode *
wbl_schema_node_ref (WblSchemaNode *self);

Increment the reference count of the schema node.

Parameters

self

a WblSchemaNode.

[transfer none]

Returns

the original schema node.

[transfer full]

Since: 0.1.0


wbl_schema_node_unref ()

void
wbl_schema_node_unref (WblSchemaNode *self);

Decrement the reference count of the schema node.

Parameters

self

a WblSchemaNode.

[transfer full]

Since: 0.1.0


wbl_schema_node_get_root ()

JsonObject *
wbl_schema_node_get_root (WblSchemaNode *self);

Get the JSON object forming the root node of this schema or subschema.

Parameters

self

a WblSchemaNode

 

Returns

schema’s root node.

[transfer none]

Since: 0.1.0


wbl_schema_node_get_title ()

const gchar *
wbl_schema_node_get_title (WblSchemaNode *self);

Get the title metadata of this schema or subschema, if set. This should briefly state the purpose of the instance produced by this schema.

Parameters

self

a WblSchemaNode

 

Returns

schema’s title, or NULL if unset.

[nullable]

Since: 0.1.0


wbl_schema_node_get_description ()

const gchar *
wbl_schema_node_get_description (WblSchemaNode *self);

Get the description metadata of this schema or subschema, if set. This should explain in depth the purpose of the instance produced by this schema.

Parameters

self

a WblSchemaNode

 

Returns

schema’s description, or NULL if unset.

[nullable]

Since: 0.1.0


wbl_schema_node_get_default ()

JsonNode *
wbl_schema_node_get_default (WblSchemaNode *self);

Get the default value for instances of this schema or subschema, if set. This may not validate against the schema.

Parameters

self

a WblSchemaNode

 

Returns

schema’s default value, or NULL if unset.

[nullable]

Since: 0.1.0


wbl_generated_instance_new_from_string ()

WblGeneratedInstance *
wbl_generated_instance_new_from_string
                               (const gchar *json,
                                gboolean valid);

Create a new WblGeneratedInstance from the given serialised JSON instance and associated metadata.

Parameters

json

serialised JSON to use for the instance

 

valid

whether the instance is expected to validate against the schema

 

Returns

newly allocated WblGeneratedInstance.

[transfer full]

Since: 0.1.0


wbl_generated_instance_copy ()

WblGeneratedInstance *
wbl_generated_instance_copy (WblGeneratedInstance *self);

Copy a WblGeneratedInstance into a newly allocated region of memory. This is a deep copy.

Parameters

self

a WblGeneratedInstance.

[transfer none]

Returns

newly allocated WblGeneratedInstance.

[transfer full]

Since: 0.1.0


wbl_generated_instance_free ()

void
wbl_generated_instance_free (WblGeneratedInstance *self);

Free an allocated WblGeneratedInstance.

Parameters

self

a WblGeneratedInstance.

[transfer full]

Since: 0.1.0


wbl_generated_instance_get_json ()

const gchar *
wbl_generated_instance_get_json (WblGeneratedInstance *self);

Get the string form of the generated JSON instance.

Parameters

Returns

string form of the generated instance

Since: 0.1.0


wbl_generated_instance_is_valid ()

gboolean
wbl_generated_instance_is_valid (WblGeneratedInstance *self);

Get whether the generated JSON instance is valid with respect to the schema.

Parameters

Returns

TRUE if valid, FALSE otherwise

Since: 0.2.0

Types and Values

WblSchema

typedef struct _WblSchema WblSchema;

All the fields in the WblSchema structure are private and should never be accessed directly.

Since: 0.1.0


WblSchemaClass

typedef struct {
	void (*validate_schema) (WblSchema *self,
	                         WblSchemaNode *root,
	                         GError **error);
	void (*apply_schema) (WblSchema *self,
	                      WblSchemaNode *root,
	                      JsonNode *instance,
	                      GError **error);
	GHashTable/*<owned JsonNode>*/ *(*generate_instance_nodes) (WblSchema      *self,
	                                                            WblSchemaNode  *root);
} WblSchemaClass;

Most of the fields in the WblSchemaClass structure are private and should never be accessed directly.

Members

validate_schema ()

Walk over a parsed schema and validate that it is a valid schema. The default implementation checks against JSON Schema, but overriding implementations could check extension keywords. If NULL, no validation will be performed.

 

apply_schema ()

Apply a parsed schema to a JSON instance, validating the instance against the schema. The default implementation applies standard JSON Schema keywords, but overriding implementations could implement extension keywords. If NULL, no application will be performed.

 

generate_instance_nodes ()

Generate a set of JSON instances which are valid and invalid for this JSON Schema. The default implementation generates for all standard JSON Schema keywords, but overriding implementations could generate for extension keywords. If NULL, no instances will be generated.

 

Since: 0.1.0


enum WblSchemaError

Error codes for WblSchema operations.

Members

WBL_SCHEMA_ERROR_MALFORMED

Loaded JSON Schema does not conform to the JSON Schema standard.

 

WBL_SCHEMA_ERROR_INVALID

Instance does not conform to the given JSON Schema.

 

Since: 0.1.0


WblSchemaNode

typedef struct _WblSchemaNode WblSchemaNode;

A reference counted structure which represents a single schema or subschema.

All the fields in the WblSchemaNode structure are private and should never be accessed directly.

Since: 0.1.0


enum WblGenerateInstanceFlags

Flags affecting the generation of JSON instances for schemas using wbl_schema_generate_instances().

Members

WBL_GENERATE_INSTANCE_NONE

No flags set.

 

WBL_GENERATE_INSTANCE_IGNORE_VALID

Do not return valid instances.

 

WBL_GENERATE_INSTANCE_IGNORE_INVALID

Do not return invalid instances.

 

WBL_GENERATE_INSTANCE_INVALID_JSON

Generate a test vector containing invalid JSON. (Since: 0.2.0)

 

Since: 0.1.0


WblGeneratedInstance

typedef struct _WblGeneratedInstance WblGeneratedInstance;

An allocated structure which represents a generated JSON instance which may be valid for a given JSON Schema. Associated metadata is stored with the instance, such as whether it is expected to be valid.

All the fields in the WblGeneratedInstance structure are private and should never be accessed directly.

Since: 0.1.0