-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
181 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.hypothesis | ||
*.egg-info | ||
venv | ||
*.pyc | ||
build | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
venv: | ||
pip install --upgrade virtualenv | ||
virtualenv --python=python3 venv | ||
|
||
install: venv | ||
. venv/bin/activate; \ | ||
pip install -e . | ||
|
||
unit-test: | ||
. venv/bin/activate; \ | ||
python -m unittest discover tests/ |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
from copy import deepcopy | ||
from random import randint | ||
|
||
from hypothesis import strategies as hs | ||
|
||
|
||
|
||
def gen_int(prop): | ||
min_value = prop.get("minimum", None) | ||
max_value = prop.get("maximum", None) | ||
return hs.integers(min_value=min_value, max_value=max_value) | ||
|
||
def gen_string(prop): | ||
return hs.text() | ||
|
||
def should_include(key, required_list): | ||
if key in required_list: | ||
return True | ||
else: | ||
return bool(randint(0, 1)) | ||
|
||
def gen_array(prop): | ||
min_value = prop.get("minimum", None) | ||
max_value = prop.get("maximum", None) | ||
|
||
if prop.get("items", {}).get("type", False) is not False: | ||
generator = get_generator(prop.get("items")) | ||
return hs.lists(elements=generator, min_size=min_value, max_size=max_value) | ||
return hs.lists(elements=gen_anything(), min_size=min_value, max_size=max_value) | ||
|
||
def gen_anything(): | ||
return hs.one_of(hs.text(), hs.booleans(), hs.integers(), hs.none()) | ||
|
||
def gen_object(prop): | ||
|
||
required = prop["required"] | ||
output = {} | ||
|
||
for k in prop["properties"].keys(): | ||
json_prop = prop["properties"][k] | ||
|
||
if should_include(k, required): | ||
output[k] = get_generator(prop["properties"][k]) | ||
|
||
return hs.fixed_dictionaries(output) | ||
|
||
def gen_enum(prop): | ||
enum = prop["enum"] | ||
return hs.sampled_from(enum) | ||
|
||
def get_generator(prop): | ||
disp = { "string": gen_string, | ||
"integer": gen_int, | ||
"number": gen_int, | ||
"object": gen_object, | ||
"array": gen_array, | ||
"enum": gen_enum, | ||
} | ||
|
||
enum = prop.get("enum", None) | ||
if enum is not None: | ||
return gen_enum(prop) | ||
|
||
|
||
json_type = prop.get("type", None) | ||
if json_type is None: | ||
raise JsonTypeError("Couldnt find type in prop {0}".format(prop)) | ||
|
||
return disp[json_type](prop) | ||
|
||
def generate_from_schema(json_schema): | ||
example_data = get_generator(json_schema) | ||
return example_data | ||
|
||
|
||
class JsonTypeError(Exception): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from setuptools import setup | ||
|
||
setup( | ||
name = 'hypo_schema', | ||
packages = ['hypo_schema'], # this must be the same as the name above | ||
version = '0.1', | ||
description = 'Generate Hypothesis generators from a json schema definition', | ||
author = 'Mark Lakewood', | ||
author_email = '[email protected]', | ||
url = 'https://github.com/mlakewood/hypo_schema', # use the URL to the github repo | ||
download_url = 'https://github.com/mlakewood/hypo_schema/tarball/0.1', # I'll explain this in a second | ||
keywords = ['testing', 'hypothesis', 'json_schema', 'generative'], # arbitrary keywords | ||
classifiers = [], | ||
install_requires=[ | ||
'jsonschema', | ||
'hypothesis', | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import unittest | ||
from pprint import pprint | ||
|
||
from jsonschema import validate | ||
|
||
from hypothesis import given, settings | ||
from hypo_schema.hypo_schema import generate_from_schema | ||
|
||
|
||
EXAMPLE_JSON_SCHEMA= { | ||
"title": "Example Schema", | ||
"type": "object", | ||
"properties": { | ||
"firstName": { | ||
"type": "string" | ||
}, | ||
"lastName": { | ||
"type": "string" | ||
}, | ||
"age": { | ||
"description": "Age in years", | ||
"type": "integer", | ||
"minimum": 0 | ||
}, | ||
"listOfElements": { | ||
"type": "array", | ||
"items": { | ||
"type": "number" | ||
} | ||
}, | ||
"listOfRandom": { | ||
"min": 4, | ||
"max": 10, | ||
"type": "array" | ||
}, | ||
"type": { | ||
"type": "string", | ||
"enum": ["string", "int", "bool"] | ||
}, | ||
"nestedMap": { | ||
"type": "object", | ||
"properties": { | ||
"firstProp": { | ||
"type": "string" | ||
} | ||
}, | ||
"required": ["firstProp"] | ||
} | ||
}, | ||
"required": ["firstName", "lastName", "nestedMap", "listOfElements"] | ||
} | ||
|
||
|
||
class TestJsonSchema(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.maxDiff = None | ||
|
||
|
||
@given(generate_from_schema(EXAMPLE_JSON_SCHEMA)) | ||
@settings(max_examples=500) | ||
def test_basic_map(self, example_data): | ||
|
||
|
||
# example_data = generate_from_schema(example_json_schema).example() | ||
# pprint(example_data) | ||
|
||
validate(example_data, EXAMPLE_JSON_SCHEMA) |