govuk_schemas 3.3.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 345030ceca3637693cb97b1f7ae278a95998880a
4
- data.tar.gz: 4b2bfb4865a81442d7ec8c18acbf83b394c2a58e
2
+ SHA256:
3
+ metadata.gz: 3b1010c2e3fc4d2b11f832cb7fc987d93bc31e911847ec6d18231e47a29a605f
4
+ data.tar.gz: 1c7c41a441859658c3f2e53ba4399374227120611150d14ca9a0d0f850e24c15
5
5
  SHA512:
6
- metadata.gz: 41557290549c44945a885bfaea6ad72cba73fef4050a9a7d1c23f89fa56a13925a598580362dfee42ff7b066664b2e018173234b4c7b120ad5dc567741e7140c
7
- data.tar.gz: 5af51d7f613812c5385f4294195dcf7fcc3184abdd85c78051d47c6654e3a7a1b0e155e84d51619cab0f15dce6d78607736f96dd4c239c118b4dd0d235f3389c
6
+ metadata.gz: 44e53cbd69991f6882e7d9a371257bef45fc100c75f945048e8700fdb9c17c9a69727219206e7ce720b5007c5412d7139472d370f856cc46fc1387453432f09b
7
+ data.tar.gz: 8ad00bb818a94cb75c5ae2d0e99ab754a204655a966a11c4acbed2e937c3015794a2847c9c5b6eb8567d2f724893c03a98fe2252c14b2499cc8d9a93b7b2e26b
@@ -0,0 +1,17 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: /
5
+ schedule:
6
+ interval: daily
7
+ allow:
8
+ # Internal gems
9
+ - dependency-name: "govuk*"
10
+ dependency-type: direct
11
+ - dependency-name: rubocop-govuk
12
+ dependency-type: direct
13
+ # Framework gems
14
+ - dependency-name: rake
15
+ dependency-type: direct
16
+ - dependency-name: rspec
17
+ dependency-type: direct
data/.rubocop.yml CHANGED
@@ -1,2 +1,6 @@
1
+ inherit_gem:
2
+ rubocop-govuk:
3
+ - config/default.yml
4
+
1
5
  AllCops:
2
- TargetRubyVersion: 2.3
6
+ TargetRubyVersion: 2.6
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.6.6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ # 4.3.0
2
+
3
+ * Generate unique items for arrays with the "uniqueItems" property. ([#63](https://github.com/alphagov/govuk_schemas/pull/63))
4
+
5
+ # 4.2.0
6
+
7
+ * Add support for generating random HH:MM time strings that match a regex. ([#62](https://github.com/alphagov/govuk_schemas/pull/62))
8
+
9
+ # 4.1.1
10
+
11
+ * Fix RandomSchemaGenerator.new always returning equivalent generators ([#60](https://github.com/alphagov/govuk_schemas/pull/60))
12
+
13
+ # 4.1.0
14
+
15
+ * 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)).
16
+
17
+ # 4.0.1
18
+
19
+ * Bump the required Ruby version to >= 2.6.x.
20
+
21
+ # 4.0.0
22
+
23
+ * Change RSpec::Matchers, rename `be_valid_against_schema` to
24
+ `be_valid_against_publisher_schema` and add
25
+ `be_valid_against_frontend_schema` plus
26
+ `be_valid_against_notification_schema`.
27
+
1
28
  # 3.3.0
2
29
 
3
30
  * Support generating objects with an `oneOf` property.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in govuk_schemas.gemspec
4
4
  gemspec
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
- try {
10
- stage('Checkout') {
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
  }
@@ -1,7 +1,6 @@
1
- # coding: utf-8
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 'govuk_schemas/version'
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 = ["lib"]
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
 
25
- spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec", "~> 3.4"
27
24
  spec.add_development_dependency "pry-byebug"
28
- spec.add_development_dependency "govuk-lint", "~> 3.11"
25
+ spec.add_development_dependency "rake", "~> 13.0"
26
+ spec.add_development_dependency "rspec", "~> 3.4"
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.3.1"
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 < Exception
12
+ class InvalidContentGenerated < RuntimeError
14
13
  end
15
14
  end
@@ -0,0 +1,128 @@
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 "^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$"
85
+ Time.now.strftime("%H:%m")
86
+ when "^#.+$"
87
+ anchor
88
+ when "[a-z-]"
89
+ random_identifier(separator: "-")
90
+ when "^[a-z_]+$"
91
+ random_identifier(separator: "_")
92
+ 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})*)?$"
93
+ base_path
94
+ 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})*)?)?$"
95
+ govuk_subdomain_url
96
+ 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})*)?)?$"
97
+ govuk_subdomain_url
98
+ when '[a-z0-9\-_]'
99
+ "#{hex}-#{hex}"
100
+ else
101
+ raise <<-DOC
102
+ Don't know how to generate random string for pattern #{pattern.inspect}
103
+
104
+ This propably means you've introduced a new regex in govuk-content-schemas.
105
+ Because it's very hard to generate a valid string from a regex alone,
106
+ we have to specify a method to generate random data for each regex in
107
+ the schemas.
108
+
109
+ To fix this:
110
+
111
+ - Add your regex to `lib/govuk_schemas/random.rb`
112
+ DOC
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def random_letter
119
+ letters = ("a".."f").to_a
120
+ letters[@random.rand(0..letters.count - 1)]
121
+ end
122
+
123
+ def random_number
124
+ numbers = ("0".."9").to_a
125
+ numbers[@random.rand(0..numbers.count - 1)]
126
+ end
127
+ end
128
+ end
@@ -1,5 +1,4 @@
1
- require "govuk_schemas/random"
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 = RandomItemGenerator.new(schema: schema)
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/random"
1
+ require "govuk_schemas/random_content_generator"
2
2
 
3
3
  module GovukSchemas
4
- # The RandomItemGenerator takes a JSON schema and outputs a random hash that
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 RandomItemGenerator
13
- def initialize(schema:)
12
+ class RandomSchemaGenerator
13
+ def initialize(schema:, seed: nil)
14
14
  @schema = schema
15
+ @random = Random.new(seed || Random.new_seed)
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['$ref'] == "#/definitions/nested_headers"
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['$ref']
35
- props.merge!(lookup_json_pointer(props['$ref']))
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['type'] || "string"
42
+ type = props["type"] || "string"
41
43
 
42
44
  # Except when it has properties, because it's defintely an object then.
43
- if props['properties']
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['anyOf']
51
- generate_value(props['anyOf'].sample)
52
- elsif props['oneOf'] && type != 'object'
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['oneOf'].sample)
59
- elsif props['allOf']
60
- props['allOf'].each_with_object({}) do |subschema, hash|
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['enum']
65
- props['enum'].sample
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
- Random.bool
75
+ @generator.bool
74
76
  elsif type == "integer"
75
- min = props['minimum'] || 0
76
- max = props['maximum'] || 10
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,71 @@ module GovukSchemas
85
87
  def generate_random_object(subschema)
86
88
  document = {}
87
89
 
88
- one_of_sample = subschema.fetch('oneOf', []).sample || {}
90
+ one_of_sample = subschema.fetch("oneOf", []).sample(random: @random) || {}
89
91
 
90
- (subschema['properties'] || {}).each do |attribute_name, attribute_properties|
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 = Random.bool \
96
- || subschema['required'].to_a.include?(attribute_name) \
97
- || (one_of_sample['required'] || {}).to_a.include?(attribute_name) \
98
- || (one_of_sample['properties'] || {}).keys.include?(attribute_name) \
99
- || subschema['minProperties'] \
100
-
101
- if should_generate_value
102
- one_of_properties = (one_of_sample['properties'] || {})[attribute_name]
103
- document[attribute_name] = if one_of_properties
104
- generate_value(one_of_properties)
105
- else
106
- generate_value(attribute_properties)
107
- end
108
- end
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['minItems'] || 0
116
- max = props['maxItems'] || 10
117
- num_items = rand(min..max)
118
-
119
- num_items.times.map do
117
+ min = props["minItems"] || 0
118
+ max = props["maxItems"] || 10
119
+ unique = props["uniqueItems"] == true
120
+ num_items = @random.rand(min..max)
121
+ items = []
122
+ attempts = 0
123
+ max_attempts = num_items * 100
124
+
125
+ until items.length == num_items
120
126
  # sometimes arrays don't have `items` specified, not sure if this is a bug
121
- generate_value(props['items'] || {})
127
+ new_value = generate_value(props["items"] || {})
128
+
129
+ if unique && items.include?(new_value)
130
+ attempts += 1
131
+ raise "Failed to create a unique array item after #{max_attempts} attempts" if attempts >= max_attempts
132
+ next
133
+ end
134
+
135
+ attempts = 0
136
+ items << new_value
122
137
  end
138
+
139
+ items
123
140
  end
124
141
 
125
142
  def generate_random_string(props)
126
143
  if props["format"]
127
- Random.string_for_type(props['format'])
144
+ @generator.string_for_type(props["format"])
128
145
  elsif props["pattern"]
129
- Random.string_for_regex(props['pattern'])
146
+ @generator.string_for_regex(props["pattern"])
130
147
  else
131
- Random.string(props['minLength'], props['maxLength'])
148
+ @generator.string(props["minLength"], props["maxLength"])
132
149
  end
133
150
  end
134
151
 
135
152
  # Look up a "pointer" like "#/definitions/title" in the schema.
136
153
  def lookup_json_pointer(ref)
137
- elements = ref.split('/')
154
+ elements = ref.split("/")
138
155
  elements.shift
139
156
  @schema.dig(*elements) || raise("Definition `#{ref}` not found in the schema")
140
157
  end
@@ -1,26 +1,16 @@
1
1
  module GovukSchemas
2
2
  module RSpecMatchers
3
- RSpec::Matchers.define :be_valid_against_schema do |schema_name|
4
- match do |item|
5
- schema = Schema.find(publisher_schema: schema_name)
6
- validator = JSON::Validator.fully_validate(schema, item)
7
- validator.empty?
8
- end
9
-
10
- failure_message do |actual|
11
- ValidationErrorMessage.new(schema_name, "schema", actual).message
12
- end
13
- end
14
-
15
- RSpec::Matchers.define :be_valid_against_links_schema do |schema_name|
16
- match do |item|
17
- schema = Schema.find(links_schema: schema_name)
18
- validator = JSON::Validator.fully_validate(schema, item)
19
- validator.empty?
20
- end
21
-
22
- failure_message do |actual|
23
- ValidationErrorMessage.new(schema_name, "links", actual).message
3
+ %w[links frontend publisher notification].each do |schema_type|
4
+ RSpec::Matchers.define "be_valid_against_#{schema_type}_schema".to_sym do |schema_name|
5
+ match do |item|
6
+ schema = Schema.find(Hash["#{schema_type}_schema".to_sym, schema_name])
7
+ validator = JSON::Validator.fully_validate(schema, item)
8
+ validator.empty?
9
+ end
10
+
11
+ failure_message do |actual|
12
+ ValidationErrorMessage.new(schema_name, "schema", actual).message
13
+ end
24
14
  end
25
15
  end
26
16
  end
@@ -36,14 +26,14 @@ module GovukSchemas
36
26
  end
37
27
 
38
28
  def message
39
- <<~doc
40
- expected the payload to be valid against the '#{schema_name}' schema:
29
+ <<~DOC
30
+ expected the payload to be valid against the '#{schema_name}' schema:
41
31
 
42
- #{formatted_payload}
32
+ #{formatted_payload}
43
33
 
44
- Validation errors:
45
- #{errors}
46
- doc
34
+ Validation errors:
35
+ #{errors}
36
+ DOC
47
37
  end
48
38
 
49
39
  private
@@ -56,6 +46,7 @@ module GovukSchemas
56
46
 
57
47
  def formatted_payload
58
48
  return payload if payload.is_a?(String)
49
+
59
50
  JSON.pretty_generate(payload)
60
51
  end
61
52
 
@@ -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").reduce({}) do |hash, file_path|
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
 
@@ -1,4 +1,4 @@
1
1
  module GovukSchemas
2
2
  # @private
3
- VERSION = "3.3.0".freeze
3
+ VERSION = "4.3.0".freeze
4
4
  end
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: 3.3.0
4
+ version: 4.3.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: 2019-07-08 00:00:00.000000000 Z
11
+ date: 2021-03-10 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: rake
28
+ name: pry-byebug
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
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: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.4'
47
+ version: '13.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: '3.4'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry-byebug
56
+ name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
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: '0'
68
+ version: '3.4'
69
69
  - !ruby/object:Gem::Dependency
70
- name: govuk-lint
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.11'
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.11'
82
+ version: '3.8'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +101,7 @@ executables: []
101
101
  extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
+ - ".github/dependabot.yml"
104
105
  - ".gitignore"
105
106
  - ".rspec"
106
107
  - ".rubocop.yml"
@@ -117,12 +118,11 @@ files:
117
118
  - lib/govuk_schemas.rb
118
119
  - lib/govuk_schemas/document_types.rb
119
120
  - lib/govuk_schemas/example.rb
120
- - lib/govuk_schemas/random.rb
121
+ - lib/govuk_schemas/random_content_generator.rb
121
122
  - lib/govuk_schemas/random_example.rb
122
- - lib/govuk_schemas/random_item_generator.rb
123
+ - lib/govuk_schemas/random_schema_generator.rb
123
124
  - lib/govuk_schemas/rspec_matchers.rb
124
125
  - lib/govuk_schemas/schema.rb
125
- - lib/govuk_schemas/utils.rb
126
126
  - lib/govuk_schemas/version.rb
127
127
  homepage: https://github.com/alphagov/govuk_schemas_gem
128
128
  licenses:
@@ -136,15 +136,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
136
  requirements:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
- version: 2.3.1
139
+ version: '2.6'
140
140
  required_rubygems_version: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  requirements: []
146
- rubyforge_project:
147
- rubygems_version: 2.5.1
146
+ rubygems_version: 3.1.4
148
147
  signing_key:
149
148
  specification_version: 4
150
149
  summary: Gem to generate test data based on GOV.UK content schemas
@@ -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
@@ -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