govuk_schemas 4.0.0 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +5 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +1 -1
- data/Jenkinsfile +3 -45
- data/govuk_schemas.gemspec +6 -7
- data/lib/govuk_schemas.rb +1 -2
- data/lib/govuk_schemas/random_content_generator.rb +126 -0
- data/lib/govuk_schemas/random_example.rb +9 -4
- data/lib/govuk_schemas/{random_item_generator.rb → random_schema_generator.rb} +48 -46
- data/lib/govuk_schemas/rspec_matchers.rb +7 -6
- data/lib/govuk_schemas/schema.rb +2 -3
- data/lib/govuk_schemas/version.rb +1 -1
- metadata +22 -24
- data/lib/govuk_schemas/random.rb +0 -101
- data/lib/govuk_schemas/utils.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f4a5f71d0e8bc0b3e6450b64b35d1048b0d357a5c6582ff852b632209f70d7b3
|
4
|
+
data.tar.gz: 94b066d781c22310f6e2781de937eacef3788a7d469447c5f48740bbf7f92eca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c2df58d688b43d6c27ffc31b29ce86ca4d0fe2f066f6dfc86aad651f2874f36290eb58168268de3fc3c81efaf118a86d4b6aed52025d749170b02b90b7696d7
|
7
|
+
data.tar.gz: d9acb23ed9baaf8b21afae83bdbcf428e973068ae81bab374c98f57897c650bec3fb3d1240cb1d8b4a5287b10111dfaa7f589d74b907975153b9b979d8fbeed1
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# 4.1.0
|
2
|
+
|
3
|
+
* Add `seed` parameter to `GovukSchemas::RandomExample` to make the random behaviour deterministic. Given the same seed, the same randomised outputs will be returned ([#56](https://github.com/alphagov/govuk_schemas/pull/56)).
|
4
|
+
|
5
|
+
# 4.0.1
|
6
|
+
|
7
|
+
* Bump the required Ruby version to >= 2.6.x.
|
8
|
+
|
1
9
|
# 4.0.0
|
2
10
|
|
3
11
|
* Change RSpec::Matchers, rename `be_valid_against_schema` to
|
data/Gemfile
CHANGED
data/Jenkinsfile
CHANGED
@@ -2,50 +2,8 @@
|
|
2
2
|
|
3
3
|
library("govuk")
|
4
4
|
|
5
|
-
REPOSITORY = 'govuk_schemas'
|
6
|
-
|
7
5
|
node {
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
checkout scm
|
12
|
-
}
|
13
|
-
|
14
|
-
stage('Clean') {
|
15
|
-
govuk.cleanupGit()
|
16
|
-
govuk.mergeMasterBranch()
|
17
|
-
}
|
18
|
-
|
19
|
-
stage("Set up content schema dependency") {
|
20
|
-
govuk.contentSchemaDependency()
|
21
|
-
}
|
22
|
-
|
23
|
-
stage('Bundle') {
|
24
|
-
echo 'Bundling'
|
25
|
-
sh("bundle install --path ${JENKINS_HOME}/bundles/${JOB_NAME}")
|
26
|
-
}
|
27
|
-
|
28
|
-
stage('Linter') {
|
29
|
-
govuk.rubyLinter()
|
30
|
-
}
|
31
|
-
|
32
|
-
stage('Tests') {
|
33
|
-
govuk.setEnvar('RAILS_ENV', 'test')
|
34
|
-
govuk.runTests('spec')
|
35
|
-
}
|
36
|
-
|
37
|
-
if(env.BRANCH_NAME == "master") {
|
38
|
-
stage('Publish Gem') {
|
39
|
-
govuk.publishGem(REPOSITORY, env.BRANCH_NAME)
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
|
-
} catch (e) {
|
44
|
-
currentBuild.result = 'FAILED'
|
45
|
-
step([$class: 'Mailer',
|
46
|
-
notifyEveryUnstableBuild: true,
|
47
|
-
recipients: 'govuk-ci-notifications@digital.cabinet-office.gov.uk',
|
48
|
-
sendToIndividuals: true])
|
49
|
-
throw e
|
50
|
-
}
|
6
|
+
govuk.buildProject(
|
7
|
+
rubyLintDiff: false,
|
8
|
+
)
|
51
9
|
}
|
data/govuk_schemas.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require "govuk_schemas/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
6
|
spec.name = "govuk_schemas"
|
@@ -17,16 +16,16 @@ Gem::Specification.new do |spec|
|
|
17
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
17
|
spec.bindir = "exe"
|
19
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = %w[lib]
|
21
20
|
|
22
21
|
# This should be kept in sync with the json-schema version of govuk-content-schemas.
|
23
22
|
spec.add_dependency "json-schema", "~> 2.8.0"
|
24
23
|
|
24
|
+
spec.add_development_dependency "pry-byebug"
|
25
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
26
|
spec.add_development_dependency "rspec", "~> 3.4"
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "govuk-lint", "~> 3.11"
|
27
|
+
spec.add_development_dependency "rubocop-govuk", "~> 3.8"
|
29
28
|
spec.add_development_dependency "yard", "~> 0.8"
|
30
29
|
|
31
|
-
spec.required_ruby_version = ">= 2.
|
30
|
+
spec.required_ruby_version = ">= 2.6"
|
32
31
|
end
|
data/lib/govuk_schemas.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "govuk_schemas/version"
|
2
2
|
require "govuk_schemas/schema"
|
3
|
-
require "govuk_schemas/utils"
|
4
3
|
require "govuk_schemas/random_example"
|
5
4
|
require "govuk_schemas/document_types"
|
6
5
|
require "govuk_schemas/example"
|
@@ -10,6 +9,6 @@ module GovukSchemas
|
|
10
9
|
CONTENT_SCHEMA_DIR = ENV["GOVUK_CONTENT_SCHEMAS_PATH"] || "../govuk-content-schemas"
|
11
10
|
|
12
11
|
# @private
|
13
|
-
class InvalidContentGenerated <
|
12
|
+
class InvalidContentGenerated < RuntimeError
|
14
13
|
end
|
15
14
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module GovukSchemas
|
2
|
+
# @private
|
3
|
+
class RandomContentGenerator
|
4
|
+
WORDS = %w[Lorem ipsum dolor sit amet consectetur adipiscing elit. Ut suscipit at mauris non bibendum. Ut ac massa est. Aenean tempor imperdiet leo vel interdum. Nam sagittis cursus sem ultricies scelerisque. Quisque porttitor risus vel risus finibus eu sollicitudin nisl aliquet. Sed sed lectus ac dolor molestie interdum. Nam molestie pellentesque purus ac vestibulum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse non tempor eros. Mauris eu orci hendrerit volutpat lorem in tristique libero. Duis a nibh nibh.].freeze
|
5
|
+
|
6
|
+
def initialize(random: Random.new)
|
7
|
+
@random = random
|
8
|
+
end
|
9
|
+
|
10
|
+
def string_for_type(type)
|
11
|
+
if type == "date-time"
|
12
|
+
time
|
13
|
+
elsif type == "uri"
|
14
|
+
uri
|
15
|
+
else
|
16
|
+
raise "Unknown attribute type `#{type}`"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def time
|
21
|
+
arbitrary_time = Time.new(2012, 2, 1)
|
22
|
+
(arbitrary_time + @random.rand(0..500_000_000)).iso8601
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO: make this more random with query string, optional anchor.
|
26
|
+
def uri
|
27
|
+
"http://example.com#{base_path}#{anchor}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def base_path
|
31
|
+
"/" + @random.rand(1..5).times.map { uuid }.join("/")
|
32
|
+
end
|
33
|
+
|
34
|
+
def govuk_subdomain_url
|
35
|
+
subdomain = @random.rand(2..4).times.map {
|
36
|
+
("a".."z").to_a.sample(@random.rand(3..8), random: @random).join
|
37
|
+
}.join(".")
|
38
|
+
"https://#{subdomain}.gov.uk#{base_path}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def string(minimum_chars = nil, maximum_chars = nil)
|
42
|
+
minimum_chars ||= 0
|
43
|
+
maximum_chars ||= 100
|
44
|
+
WORDS.sample(@random.rand(minimum_chars..maximum_chars), random: @random).join(" ")
|
45
|
+
end
|
46
|
+
|
47
|
+
def bool
|
48
|
+
@random.rand(2) == 1
|
49
|
+
end
|
50
|
+
|
51
|
+
def anchor
|
52
|
+
"##{hex}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def random_identifier(separator:)
|
56
|
+
WORDS.sample(@random.rand(1..10), random: @random)
|
57
|
+
.join("-")
|
58
|
+
.gsub(/[^a-z0-9\-_]+/i, "-")
|
59
|
+
.gsub("-", separator)
|
60
|
+
end
|
61
|
+
|
62
|
+
def uuid
|
63
|
+
# matches uuid regex e.g. e058aad7-ce86-5181-8801-4ddcb3c8f27c
|
64
|
+
# /^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/
|
65
|
+
"#{hex(8)}-#{hex(4)}-1#{hex(3)}-a#{hex(3)}-#{hex(12)}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def hex(length = 10)
|
69
|
+
length.times.map { bool ? random_letter : random_number }.join("")
|
70
|
+
end
|
71
|
+
|
72
|
+
def string_for_regex(pattern)
|
73
|
+
case pattern.to_s
|
74
|
+
when "^(placeholder|placeholder_.+)$"
|
75
|
+
["placeholder", "placeholder_#{WORDS.sample(random: @random)}"].sample(random: @random)
|
76
|
+
when "^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$"
|
77
|
+
uuid
|
78
|
+
when "^/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?$"
|
79
|
+
base_path
|
80
|
+
when "^[1-9][0-9]{3}[-/](0[1-9]|1[0-2])[-/](0[1-9]|[12][0-9]|3[0-1])$"
|
81
|
+
Date.today.iso8601
|
82
|
+
when "^[1-9][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[0-1])$"
|
83
|
+
Date.today.iso8601
|
84
|
+
when "^#.+$"
|
85
|
+
anchor
|
86
|
+
when "[a-z-]"
|
87
|
+
random_identifier(separator: "-")
|
88
|
+
when "^[a-z_]+$"
|
89
|
+
random_identifier(separator: "_")
|
90
|
+
when "^/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?$"
|
91
|
+
base_path
|
92
|
+
when "^https://([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[A-Za-z0-9])?\\.)+campaign\\.gov\\.uk(/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?)?$"
|
93
|
+
govuk_subdomain_url
|
94
|
+
when "^https://([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[A-Za-z0-9])?\\.)*gov\\.uk(/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?)?$"
|
95
|
+
govuk_subdomain_url
|
96
|
+
when '[a-z0-9\-_]'
|
97
|
+
"#{hex}-#{hex}"
|
98
|
+
else
|
99
|
+
raise <<-DOC
|
100
|
+
Don't know how to generate random string for pattern #{pattern.inspect}
|
101
|
+
|
102
|
+
This propably means you've introduced a new regex in govuk-content-schemas.
|
103
|
+
Because it's very hard to generate a valid string from a regex alone,
|
104
|
+
we have to specify a method to generate random data for each regex in
|
105
|
+
the schemas.
|
106
|
+
|
107
|
+
To fix this:
|
108
|
+
|
109
|
+
- Add your regex to `lib/govuk_schemas/random.rb`
|
110
|
+
DOC
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def random_letter
|
117
|
+
letters = ("a".."f").to_a
|
118
|
+
letters[@random.rand(0..letters.count - 1)]
|
119
|
+
end
|
120
|
+
|
121
|
+
def random_number
|
122
|
+
numbers = ("0".."9").to_a
|
123
|
+
numbers[@random.rand(0..numbers.count - 1)]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require "govuk_schemas/
|
2
|
-
require "govuk_schemas/random_item_generator"
|
1
|
+
require "govuk_schemas/random_schema_generator"
|
3
2
|
require "json-schema"
|
4
3
|
require "json"
|
5
4
|
|
@@ -24,11 +23,17 @@ module GovukSchemas
|
|
24
23
|
# schema = GovukSchemas::Schema.find(frontend_schema: "detailed_guide")
|
25
24
|
# GovukSchemas::RandomExample.new(schema: schema).payload
|
26
25
|
#
|
26
|
+
# Example with seed (for consistent results):
|
27
|
+
#
|
28
|
+
# schema = GovukSchemas::Schema.find(frontend_schema: "detailed_guide")
|
29
|
+
# GovukSchemas::RandomExample.new(schema: schema, seed: 777).payload
|
30
|
+
# GovukSchemas::RandomExample.new(schema: schema, seed: 777).payload # returns same as above
|
31
|
+
#
|
27
32
|
# @param [Hash] schema A JSON schema.
|
28
33
|
# @return [GovukSchemas::RandomExample]
|
29
|
-
def initialize(schema:)
|
34
|
+
def initialize(schema:, seed: nil)
|
30
35
|
@schema = schema
|
31
|
-
@random_generator =
|
36
|
+
@random_generator = RandomSchemaGenerator.new(schema: schema, seed: seed)
|
32
37
|
end
|
33
38
|
|
34
39
|
# Returns a new `GovukSchemas::RandomExample` object.
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require "govuk_schemas/
|
1
|
+
require "govuk_schemas/random_content_generator"
|
2
2
|
|
3
3
|
module GovukSchemas
|
4
|
-
# The
|
4
|
+
# The RandomSchemaGenerator takes a JSON schema and outputs a random hash that
|
5
5
|
# is valid against said schema.
|
6
6
|
#
|
7
7
|
# The "randomness" here is quote relative, it's particularly tailored to the
|
@@ -9,9 +9,11 @@ module GovukSchemas
|
|
9
9
|
# hundred characters to keep the resulting items small.
|
10
10
|
#
|
11
11
|
# @private
|
12
|
-
class
|
13
|
-
def initialize(schema:)
|
12
|
+
class RandomSchemaGenerator
|
13
|
+
def initialize(schema:, seed: nil)
|
14
14
|
@schema = schema
|
15
|
+
@random = Random.new(seed || rand)
|
16
|
+
@generator = RandomContentGenerator.new(random: @random)
|
15
17
|
end
|
16
18
|
|
17
19
|
def payload
|
@@ -24,45 +26,45 @@ module GovukSchemas
|
|
24
26
|
# TODO: #/definitions/nested_headers are recursively nested and can cause
|
25
27
|
# infinite loops. We need to add something that detects and prevents the
|
26
28
|
# loop. In the meantime return a valid value.
|
27
|
-
if props[
|
29
|
+
if props["$ref"] == "#/definitions/nested_headers"
|
28
30
|
return [{ "text" => "1", "level" => 1, "id" => "ABC" }]
|
29
31
|
end
|
30
32
|
|
31
33
|
# JSON schemas can have "pointers". We use this to extract defintions and
|
32
34
|
# reduce duplication. To make the schema easily parsable we inline the
|
33
35
|
# reference here.
|
34
|
-
if props[
|
35
|
-
props.merge!(lookup_json_pointer(props[
|
36
|
+
if props["$ref"]
|
37
|
+
props.merge!(lookup_json_pointer(props["$ref"]))
|
36
38
|
end
|
37
39
|
|
38
40
|
# Attributes with `enum` specified often omit the `type` from
|
39
41
|
# their definition. It's most likely a string.
|
40
|
-
type = props[
|
42
|
+
type = props["type"] || "string"
|
41
43
|
|
42
44
|
# Except when it has properties, because it's defintely an object then.
|
43
|
-
if props[
|
45
|
+
if props["properties"]
|
44
46
|
type = "object"
|
45
47
|
end
|
46
48
|
|
47
49
|
# Make sure that we choose a type when there are more than one specified.
|
48
|
-
type = Array(type).sample
|
50
|
+
type = Array(type).sample(random: @random)
|
49
51
|
|
50
|
-
if props[
|
51
|
-
generate_value(props[
|
52
|
-
elsif props[
|
52
|
+
if props["anyOf"]
|
53
|
+
generate_value(props["anyOf"].sample(random: @random))
|
54
|
+
elsif props["oneOf"] && type != "object"
|
53
55
|
# FIXME: Generating valid data for a `oneOf` schema is quite interesting.
|
54
56
|
# According to the JSON Schema spec a `oneOf` schema is only valid if
|
55
57
|
# the data is valid against *only one* of the clauses. To do this
|
56
58
|
# properly, we'd have to verify that the data generated below doesn't
|
57
59
|
# validate against the other schemas in `props['oneOf']`.
|
58
|
-
generate_value(props[
|
59
|
-
elsif props[
|
60
|
-
props[
|
60
|
+
generate_value(props["oneOf"].sample(random: @random))
|
61
|
+
elsif props["allOf"]
|
62
|
+
props["allOf"].each_with_object({}) do |subschema, hash|
|
61
63
|
val = generate_value(subschema)
|
62
64
|
hash.merge(val)
|
63
65
|
end
|
64
|
-
elsif props[
|
65
|
-
props[
|
66
|
+
elsif props["enum"]
|
67
|
+
props["enum"].sample(random: @random)
|
66
68
|
elsif type == "null"
|
67
69
|
nil
|
68
70
|
elsif type == "object"
|
@@ -70,11 +72,11 @@ module GovukSchemas
|
|
70
72
|
elsif type == "array"
|
71
73
|
generate_random_array(props)
|
72
74
|
elsif type == "boolean"
|
73
|
-
|
75
|
+
@generator.bool
|
74
76
|
elsif type == "integer"
|
75
|
-
min = props[
|
76
|
-
max = props[
|
77
|
-
rand(min..max)
|
77
|
+
min = props["minimum"] || 0
|
78
|
+
max = props["maximum"] || 10
|
79
|
+
@random.rand(min..max)
|
78
80
|
elsif type == "string"
|
79
81
|
generate_random_string(props)
|
80
82
|
else
|
@@ -85,56 +87,56 @@ module GovukSchemas
|
|
85
87
|
def generate_random_object(subschema)
|
86
88
|
document = {}
|
87
89
|
|
88
|
-
one_of_sample = subschema.fetch(
|
90
|
+
one_of_sample = subschema.fetch("oneOf", []).sample(random: @random) || {}
|
89
91
|
|
90
|
-
(subschema[
|
92
|
+
(subschema["properties"] || {}).each do |attribute_name, attribute_properties|
|
91
93
|
# TODO: When the schema contains `subschema['minProperties']` we always
|
92
94
|
# populate all of the keys in the hash. This isn't quite random, but I
|
93
95
|
# haven't found a nice way yet to ensure there's at least n elements in
|
94
96
|
# the hash.
|
95
|
-
should_generate_value =
|
96
|
-
|| subschema[
|
97
|
-
|| (one_of_sample[
|
98
|
-
|| (one_of_sample[
|
99
|
-
|| subschema[
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
97
|
+
should_generate_value = @generator.bool \
|
98
|
+
|| subschema["required"].to_a.include?(attribute_name) \
|
99
|
+
|| (one_of_sample["required"] || {}).to_a.include?(attribute_name) \
|
100
|
+
|| (one_of_sample["properties"] || {}).keys.include?(attribute_name) \
|
101
|
+
|| subschema["minProperties"] \
|
102
|
+
|
103
|
+
next unless should_generate_value
|
104
|
+
|
105
|
+
one_of_properties = (one_of_sample["properties"] || {})[attribute_name]
|
106
|
+
document[attribute_name] = if one_of_properties
|
107
|
+
generate_value(one_of_properties)
|
108
|
+
else
|
109
|
+
generate_value(attribute_properties)
|
110
|
+
end
|
109
111
|
end
|
110
112
|
|
111
113
|
document
|
112
114
|
end
|
113
115
|
|
114
116
|
def generate_random_array(props)
|
115
|
-
min = props[
|
116
|
-
max = props[
|
117
|
-
num_items = rand(min..max)
|
117
|
+
min = props["minItems"] || 0
|
118
|
+
max = props["maxItems"] || 10
|
119
|
+
num_items = @random.rand(min..max)
|
118
120
|
|
119
121
|
num_items.times.map do
|
120
122
|
# sometimes arrays don't have `items` specified, not sure if this is a bug
|
121
|
-
generate_value(props[
|
123
|
+
generate_value(props["items"] || {})
|
122
124
|
end
|
123
125
|
end
|
124
126
|
|
125
127
|
def generate_random_string(props)
|
126
128
|
if props["format"]
|
127
|
-
|
129
|
+
@generator.string_for_type(props["format"])
|
128
130
|
elsif props["pattern"]
|
129
|
-
|
131
|
+
@generator.string_for_regex(props["pattern"])
|
130
132
|
else
|
131
|
-
|
133
|
+
@generator.string(props["minLength"], props["maxLength"])
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
135
137
|
# Look up a "pointer" like "#/definitions/title" in the schema.
|
136
138
|
def lookup_json_pointer(ref)
|
137
|
-
elements = ref.split(
|
139
|
+
elements = ref.split("/")
|
138
140
|
elements.shift
|
139
141
|
@schema.dig(*elements) || raise("Definition `#{ref}` not found in the schema")
|
140
142
|
end
|
@@ -26,14 +26,14 @@ module GovukSchemas
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def message
|
29
|
-
<<~
|
30
|
-
|
29
|
+
<<~DOC
|
30
|
+
expected the payload to be valid against the '#{schema_name}' schema:
|
31
31
|
|
32
|
-
|
32
|
+
#{formatted_payload}
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
Validation errors:
|
35
|
+
#{errors}
|
36
|
+
DOC
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
@@ -46,6 +46,7 @@ module GovukSchemas
|
|
46
46
|
|
47
47
|
def formatted_payload
|
48
48
|
return payload if payload.is_a?(String)
|
49
|
+
|
49
50
|
JSON.pretty_generate(payload)
|
50
51
|
end
|
51
52
|
|
data/lib/govuk_schemas/schema.rb
CHANGED
@@ -19,11 +19,10 @@ module GovukSchemas
|
|
19
19
|
#
|
20
20
|
# @param schema_type [String] The type: frontend, publisher, notification or links
|
21
21
|
# @return [Array<Hash>] List of JSON schemas as hashes
|
22
|
-
def self.all(schema_type:
|
22
|
+
def self.all(schema_type: "*")
|
23
23
|
schema_type = "publisher_v2" if schema_type == "publisher"
|
24
|
-
Dir.glob("#{GovukSchemas::CONTENT_SCHEMA_DIR}/dist/formats/*/#{schema_type}/*.json").
|
24
|
+
Dir.glob("#{GovukSchemas::CONTENT_SCHEMA_DIR}/dist/formats/*/#{schema_type}/*.json").each_with_object({}) do |file_path, hash|
|
25
25
|
hash[file_path] = JSON.parse(File.read(file_path))
|
26
|
-
hash
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: govuk_schemas
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GOV.UK Dev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json-schema
|
@@ -25,61 +25,61 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 2.8.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pry-byebug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '10.0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '10.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '3.4'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '3.4'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: govuk
|
70
|
+
name: rubocop-govuk
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
75
|
+
version: '3.8'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
82
|
+
version: '3.8'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: yard
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,12 +117,11 @@ files:
|
|
117
117
|
- lib/govuk_schemas.rb
|
118
118
|
- lib/govuk_schemas/document_types.rb
|
119
119
|
- lib/govuk_schemas/example.rb
|
120
|
-
- lib/govuk_schemas/
|
120
|
+
- lib/govuk_schemas/random_content_generator.rb
|
121
121
|
- lib/govuk_schemas/random_example.rb
|
122
|
-
- lib/govuk_schemas/
|
122
|
+
- lib/govuk_schemas/random_schema_generator.rb
|
123
123
|
- lib/govuk_schemas/rspec_matchers.rb
|
124
124
|
- lib/govuk_schemas/schema.rb
|
125
|
-
- lib/govuk_schemas/utils.rb
|
126
125
|
- lib/govuk_schemas/version.rb
|
127
126
|
homepage: https://github.com/alphagov/govuk_schemas_gem
|
128
127
|
licenses:
|
@@ -136,15 +135,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
135
|
requirements:
|
137
136
|
- - ">="
|
138
137
|
- !ruby/object:Gem::Version
|
139
|
-
version: 2.
|
138
|
+
version: '2.6'
|
140
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
140
|
requirements:
|
142
141
|
- - ">="
|
143
142
|
- !ruby/object:Gem::Version
|
144
143
|
version: '0'
|
145
144
|
requirements: []
|
146
|
-
|
147
|
-
rubygems_version: 2.5.1
|
145
|
+
rubygems_version: 3.0.3
|
148
146
|
signing_key:
|
149
147
|
specification_version: 4
|
150
148
|
summary: Gem to generate test data based on GOV.UK content schemas
|
data/lib/govuk_schemas/random.rb
DELETED
@@ -1,101 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
|
-
module GovukSchemas
|
4
|
-
# @private
|
5
|
-
module Random
|
6
|
-
class << self
|
7
|
-
WORDS = %w[Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut suscipit at mauris non bibendum. Ut ac massa est. Aenean tempor imperdiet leo vel interdum. Nam sagittis cursus sem ultricies scelerisque. Quisque porttitor risus vel risus finibus, eu sollicitudin nisl aliquet. Sed sed lectus ac dolor molestie interdum. Nam molestie pellentesque purus ac vestibulum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse non tempor eros. Mauris eu orci hendrerit, volutpat lorem in, tristique libero. Duis a nibh nibh.].freeze
|
8
|
-
|
9
|
-
def string_for_type(type)
|
10
|
-
if type == 'date-time'
|
11
|
-
time
|
12
|
-
elsif type == 'uri'
|
13
|
-
uri
|
14
|
-
else
|
15
|
-
raise "Unknown attribute type `#{type}`"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def time
|
20
|
-
seconds_ago = rand(10_000_000) - 5_000_000
|
21
|
-
(Time.now + seconds_ago).iso8601
|
22
|
-
end
|
23
|
-
|
24
|
-
# TODO: make this more random with query string, optional anchor.
|
25
|
-
def uri
|
26
|
-
"http://example.com#{base_path}#{anchor}"
|
27
|
-
end
|
28
|
-
|
29
|
-
def base_path
|
30
|
-
"/" + rand(1..5).times.map { SecureRandom.uuid }.join('/')
|
31
|
-
end
|
32
|
-
|
33
|
-
def govuk_subdomain_url
|
34
|
-
subdomain = rand(2..4).times.map {
|
35
|
-
('a'..'z').to_a.sample(rand(3..8)).join
|
36
|
-
}.join('.')
|
37
|
-
"https://#{subdomain}.gov.uk#{base_path}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def string(minimum_chars = nil, maximum_chars = nil)
|
41
|
-
minimum_chars = minimum_chars || 0
|
42
|
-
maximum_chars = maximum_chars || 100
|
43
|
-
WORDS.sample(rand(minimum_chars..maximum_chars)).join(' ')
|
44
|
-
end
|
45
|
-
|
46
|
-
def bool
|
47
|
-
rand(2) == 1
|
48
|
-
end
|
49
|
-
|
50
|
-
def anchor
|
51
|
-
"##{SecureRandom.hex}"
|
52
|
-
end
|
53
|
-
|
54
|
-
def random_identifier(separator:)
|
55
|
-
Utils.parameterize(WORDS.sample(rand(1..10)).join('-')).gsub('-', separator)
|
56
|
-
end
|
57
|
-
|
58
|
-
def string_for_regex(pattern)
|
59
|
-
case pattern.to_s
|
60
|
-
when '^(placeholder|placeholder_.+)$'
|
61
|
-
['placeholder', "placeholder_#{WORDS.sample}"].sample
|
62
|
-
when '^[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$'
|
63
|
-
SecureRandom.uuid
|
64
|
-
when "^/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?$"
|
65
|
-
base_path
|
66
|
-
when "^[1-9][0-9]{3}[-/](0[1-9]|1[0-2])[-/](0[1-9]|[12][0-9]|3[0-1])$"
|
67
|
-
Date.today.iso8601
|
68
|
-
when "^[1-9][0-9]{3}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[0-1])$"
|
69
|
-
Date.today.iso8601
|
70
|
-
when "^#.+$"
|
71
|
-
anchor
|
72
|
-
when "[a-z-]"
|
73
|
-
random_identifier(separator: '-')
|
74
|
-
when "^[a-z_]+$"
|
75
|
-
random_identifier(separator: '_')
|
76
|
-
when "^/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?$"
|
77
|
-
base_path
|
78
|
-
when "^https://([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[A-Za-z0-9])?\\.)+campaign\\.gov\\.uk(/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?)?$"
|
79
|
-
govuk_subdomain_url
|
80
|
-
when "^https://([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[A-Za-z0-9])?\\.)*gov\\.uk(/(([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})+(/([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)*)?(\\?([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?(#([a-zA-Z0-9._~!$&'()*+,;=:@-]|%[0-9a-fA-F]{2})*)?)?$"
|
81
|
-
govuk_subdomain_url
|
82
|
-
when '[a-z0-9\-_]'
|
83
|
-
"#{SecureRandom.hex}-#{SecureRandom.hex}"
|
84
|
-
else
|
85
|
-
raise <<-doc
|
86
|
-
Don't know how to generate random string for pattern #{pattern.inspect}
|
87
|
-
|
88
|
-
This propably means you've introduced a new regex in govuk-content-schemas.
|
89
|
-
Because it's very hard to generate a valid string from a regex alone,
|
90
|
-
we have to specify a method to generate random data for each regex in
|
91
|
-
the schemas.
|
92
|
-
|
93
|
-
To fix this:
|
94
|
-
|
95
|
-
- Add your regex to `lib/govuk_schemas/random.rb`
|
96
|
-
doc
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
data/lib/govuk_schemas/utils.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
module GovukSchemas
|
2
|
-
# @private
|
3
|
-
module Utils
|
4
|
-
def self.stringify_keys(hash)
|
5
|
-
new_hash = {}
|
6
|
-
hash.each do |k, v|
|
7
|
-
new_hash[k.to_s] = v
|
8
|
-
end
|
9
|
-
new_hash
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.parameterize(string)
|
13
|
-
string.gsub(/[^a-z0-9\-_]+/i, '-')
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|