From ec1be05dc05f61bba17c5e4981c8a4fb43dba3a0 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Tue, 13 Aug 2024 15:56:05 +0100 Subject: [PATCH] feat: add v3/v4 generators (thanks @slt) --- README.md | 45 ++++++ lib/pact/from_provider_state.rb | 133 ++++++++++++++++++ lib/pact/generator/date.rb | 62 ++++++++ lib/pact/generator/datetime.rb | 16 +++ lib/pact/generator/provider_state.rb | 53 +++++++ lib/pact/generator/random_boolean.rb | 14 ++ lib/pact/generator/random_decimal.rb | 37 +++++ lib/pact/generator/random_hexadecimal.rb | 19 +++ lib/pact/generator/random_int.rb | 16 +++ lib/pact/generator/random_string.rb | 16 +++ lib/pact/generator/regex.rb | 17 +++ lib/pact/generator/time.rb | 16 +++ lib/pact/generator/uuid.rb | 19 +++ lib/pact/generators.rb | 64 +++++++++ pact-support.gemspec | 2 + spec/lib/pact/generator/date_spec.rb | 20 +++ spec/lib/pact/generator/datetime_spec.rb | 21 +++ .../lib/pact/generator/provider_state_spec.rb | 37 +++++ .../lib/pact/generator/random_boolean_spec.rb | 20 +++ .../lib/pact/generator/random_decimal_spec.rb | 27 ++++ .../pact/generator/random_hexadecimal_spec.rb | 25 ++++ spec/lib/pact/generator/random_int_spec.rb | 25 ++++ spec/lib/pact/generator/random_string_spec.rb | 25 ++++ spec/lib/pact/generator/regex_spec.rb | 20 +++ spec/lib/pact/generator/time_spec.rb | 20 +++ spec/lib/pact/generator/uuid_spec.rb | 20 +++ spec/lib/pact/generators_spec.rb | 59 ++++++++ .../matchers/matchers_provider_param_spec.rb | 19 +++ spec/lib/pact/provider_param_spec.rb | 44 ++++++ 29 files changed, 911 insertions(+) create mode 100644 lib/pact/from_provider_state.rb create mode 100644 lib/pact/generator/date.rb create mode 100644 lib/pact/generator/datetime.rb create mode 100644 lib/pact/generator/provider_state.rb create mode 100644 lib/pact/generator/random_boolean.rb create mode 100644 lib/pact/generator/random_decimal.rb create mode 100644 lib/pact/generator/random_hexadecimal.rb create mode 100644 lib/pact/generator/random_int.rb create mode 100644 lib/pact/generator/random_string.rb create mode 100644 lib/pact/generator/regex.rb create mode 100644 lib/pact/generator/time.rb create mode 100644 lib/pact/generator/uuid.rb create mode 100644 lib/pact/generators.rb create mode 100644 spec/lib/pact/generator/date_spec.rb create mode 100644 spec/lib/pact/generator/datetime_spec.rb create mode 100644 spec/lib/pact/generator/provider_state_spec.rb create mode 100644 spec/lib/pact/generator/random_boolean_spec.rb create mode 100644 spec/lib/pact/generator/random_decimal_spec.rb create mode 100644 spec/lib/pact/generator/random_hexadecimal_spec.rb create mode 100644 spec/lib/pact/generator/random_int_spec.rb create mode 100644 spec/lib/pact/generator/random_string_spec.rb create mode 100644 spec/lib/pact/generator/regex_spec.rb create mode 100644 spec/lib/pact/generator/time_spec.rb create mode 100644 spec/lib/pact/generator/uuid_spec.rb create mode 100644 spec/lib/pact/generators_spec.rb create mode 100644 spec/lib/pact/matchers/matchers_provider_param_spec.rb create mode 100644 spec/lib/pact/provider_param_spec.rb diff --git a/README.md b/README.md index a45d3dd..9967980 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,48 @@ ![Build status](https://github.com/pact-foundation/pact-support/workflows/Test/badge.svg) Provides shared code for the Pact gems + +## Supported matching rules + +| matcher | Spec Version | Implemented | Usage| +|---------------|--------------|-------------|-------------| +| Equality | V1 | | | +| Regex | V2 | ✅ | `Pact.term(generate, matcher)` | +| Type | V2 | ✅ | `Pact.like(generate)` | +| MinType | V2 | ✅ | `Pact.each_like(generate, min: )` | +| MaxType | V2 | | | +| MinMaxType | V2 | | | +| Include | V3 | | | +| Integer | V3 | | | +| Decimal | V3 | | | +| Number | V3 | | | +| Timestamp | V3 | | | +| Time | V3 | | | +| Date | V3 | | | +| Null | V3 | | | +| Boolean | V3 | | | +| ContentType | V3 | | | +| Values | V3 | | | +| ArrayContains | V4 | | | +| StatusCode | V4 | | | +| NotEmpty | V4 | | | +| Semver | V4 | | | +| EachKey | V4 | | | +| EachValue | V4 | | | + +## Supported generators + +| matcher | Spec Version | Implemented | +|------------------------|--------------|----| +| RandomInt | V3 | ✅ | +| RandomDecimal | V3 | ✅ | +| RandomHexadecimal | V3 | ✅ | +| RandomString | V3 | ✅ | +| Regex | V3 | ✅ | +| Uuid | V3/V4 | ✅ | +| Date | V3 | ✅ | +| Time | V3 | ✅ | +| DateTime | V3 | ✅ | +| RandomBoolean | V3 | ✅ | +| ProviderState | V4 | ✅ | +| MockServerURL | V4 | 🚧 | diff --git a/lib/pact/from_provider_state.rb b/lib/pact/from_provider_state.rb new file mode 100644 index 0000000..f8af14e --- /dev/null +++ b/lib/pact/from_provider_state.rb @@ -0,0 +1,133 @@ +require 'pact/shared/active_support_support' + +module Pact + class FromProviderState + include Pact::ActiveSupportSupport + + attr_reader :expression, :default_string, :params + + def self.json_create(obj) + new(obj['data']['expression'], obj['data']['params']) + end + + def initialize(expression, arg2) + @expression = expression + if arg2.is_a? String + @default_string = arg2 + @params = find_default_values + else + @params = stringify_params(arg2) + @default_string = default_string_from_params @params + end + end + + def replace_params(params) + @params = stringify_params(params) + @default_string = default_string_from_params @params + end + + def to_hash + { json_class: self.class.name, data: { expression: @expression, params: @params } } + end + + def as_json + to_hash + end + + def to_json(options = {}) + as_json.to_json(options) + end + + def ==(other) + return false if !other.respond_to?(:expression) || other.expression != @expression + return false if !other.respond_to?(:params) || other.params != @params + + true + end + + def to_s + "Pact::FromProviderState: #{@expression} #{@params}" + end + + def empty? + false + end + + private + + def stringify_params(params) + stringified_params = {} + params.each { |k, v| stringified_params[k.to_s] = v } + stringified_params + end + + def param_name_regex + /\${[a-zA-Z0-9_-]+}/ + end + + def parse_expression + matches = @expression.scan(param_name_regex) + matches.map do |match| + match[2..(match.length - 2)] + end + end + + def find_strings_between_variables(_var_names) + in_between_strings = [] + previous_string_end = 0 + matches = @expression.scan(param_name_regex) + + matches.size.times do |index| + # get the locations of the string in between the matched variable names + variable_name_start = @expression.index(matches[index]) + variable_name_end = variable_name_start + matches[index].length + string_text = @expression[previous_string_end...variable_name_start] + previous_string_end = variable_name_end + in_between_strings << string_text unless string_text.empty? + end + last_part = @expression[previous_string_end...@expression.length] + in_between_strings << last_part unless last_part.empty? + + in_between_strings + end + + def find_variable_values_in_default_string(in_between_strings) + previous_value_end = 0 + values = [] + + in_between_strings.each do |string| + string_start = @default_string.index(string) + value = @default_string[previous_value_end...string_start] + values << value unless string_start == 0 + previous_value_end = string_start + string.length + end + + last_string = @default_string[previous_value_end..@default_string.length - 1] + values << last_string unless last_string.empty? + + values + end + + def find_default_values + var_names = parse_expression + in_between_strings = find_strings_between_variables(var_names) + + values = find_variable_values_in_default_string(in_between_strings) + + param_hash = {} + new_params_arr = var_names.zip(values) + new_params_arr.each do |key, value| + param_hash[key] = value + end + param_hash + end + + def default_string_from_params(params) + default_string = @expression + params.each do |key, value| + default_string = default_string.gsub('${' + key + '}', value) + end + default_string + end + end +end diff --git a/lib/pact/generator/date.rb b/lib/pact/generator/date.rb new file mode 100644 index 0000000..d444241 --- /dev/null +++ b/lib/pact/generator/date.rb @@ -0,0 +1,62 @@ +require 'date' + +module Pact + module Generator + # Date provides the time generator which will give the current date in the defined format + class Date + def can_generate?(hash) + hash.key?('type') && hash['type'] == type + end + + def call(hash, _params = nil, _example_value = nil) + format = hash['format'] || default_format + ::Time.now.strftime(convert_from_java_simple_date_format(format)) + end + + def type + 'Date' + end + + def default_format + 'yyyy-MM-dd' + end + + # Format for the pact specficiation should be the Java DateTimeFormmater + # This tries to convert to something Ruby can format. + def convert_from_java_simple_date_format(format) + # Year + format.sub!(/(?= 0 + if position.positive? + # add string + return_string.push(buffer[0...position]) + end + end_position = buffer.index(END_EXPRESSION, position) + raise 'Missing closing brace in expression string' if !end_position || end_position.negative? + + variable = buffer[position + 2...end_position] + + logger.info "Could not subsitute provider state key #{variable}, have #{params}" unless params[variable] + + expression = params[variable] || '' + return_string.push(expression) + + buffer = buffer[end_position + 1...-1] + position = buffer.index(START_EXPRESSION) + end + + return_string.join('') + end + end + end +end diff --git a/lib/pact/generator/random_boolean.rb b/lib/pact/generator/random_boolean.rb new file mode 100644 index 0000000..beb1224 --- /dev/null +++ b/lib/pact/generator/random_boolean.rb @@ -0,0 +1,14 @@ +module Pact + module Generator + # Boolean provides the boolean generator which will give a true or false value + class RandomBoolean + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomBoolean' + end + + def call(_hash, _params = nil, _example_value = nil) + [true, false].sample + end + end + end +end diff --git a/lib/pact/generator/random_decimal.rb b/lib/pact/generator/random_decimal.rb new file mode 100644 index 0000000..f255989 --- /dev/null +++ b/lib/pact/generator/random_decimal.rb @@ -0,0 +1,37 @@ +require 'bigdecimal' + +module Pact + module Generator + # RandomDecimal provides the random decimal generator which will generate a decimal value of digits length + class RandomDecimal + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomDecimal' + end + + def call(hash, _params = nil, _example_value = nil) + digits = hash['digits'] || 6 + + raise 'RandomDecimalGenerator digits must be > 0, got $digits' if digits < 1 + + return rand(0..9) if digits == 1 + + return rand(0..9) + rand(1..9) / 10 if digits == 2 + + pos = rand(1..digits - 1) + precision = digits - pos + integers = '' + decimals = '' + while pos.positive? + integers += String(rand(1..9)) + pos -= 1 + end + while precision.positive? + decimals += String(rand(1..9)) + precision -= 1 + end + + Float("#{integers}.#{decimals}") + end + end + end +end diff --git a/lib/pact/generator/random_hexadecimal.rb b/lib/pact/generator/random_hexadecimal.rb new file mode 100644 index 0000000..b90a3de --- /dev/null +++ b/lib/pact/generator/random_hexadecimal.rb @@ -0,0 +1,19 @@ +require 'securerandom' + +module Pact + module Generator + # RandomHexadecimal provides the random hexadecimal generator which will generate a hexadecimal + class RandomHexadecimal + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomHexadecimal' + end + + def call(hash, _params = nil, _example_value = nil) + digits = hash['digits'] || 8 + bytes = (digits / 2).ceil + string = SecureRandom.hex(bytes) + string[0, digits] + end + end + end +end diff --git a/lib/pact/generator/random_int.rb b/lib/pact/generator/random_int.rb new file mode 100644 index 0000000..fc157be --- /dev/null +++ b/lib/pact/generator/random_int.rb @@ -0,0 +1,16 @@ +module Pact + module Generator + # RandomInt provides the random int generator which generate a random integer, with a min/max + class RandomInt + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomInt' + end + + def call(hash, _params = nil, _example_value = nil) + min = hash['min'] || 0 + max = hash['max'] || 2_147_483_647 + rand(min..max) + end + end + end +end diff --git a/lib/pact/generator/random_string.rb b/lib/pact/generator/random_string.rb new file mode 100644 index 0000000..e61c57a --- /dev/null +++ b/lib/pact/generator/random_string.rb @@ -0,0 +1,16 @@ +module Pact + module Generator + # RandomString provides the random string generator which generate a random string of size length + class RandomString + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'RandomString' + end + + def call(hash, _params = nil, _example_value = nil) + size = hash['size'] || 20 + string = rand(36**(size + 2)).to_s(36) + string[0, size] + end + end + end +end diff --git a/lib/pact/generator/regex.rb b/lib/pact/generator/regex.rb new file mode 100644 index 0000000..eb587b2 --- /dev/null +++ b/lib/pact/generator/regex.rb @@ -0,0 +1,17 @@ +require 'string_pattern' + +module Pact + module Generator + # Regex provides the regex generator which will generate a value based on the regex pattern provided + class Regex + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'Regex' + end + + def call(hash, _params = nil, _example_value = nil) + pattern = hash['pattern'] || '' + StringPattern.generate(Regexp.new(pattern)) + end + end + end +end diff --git a/lib/pact/generator/time.rb b/lib/pact/generator/time.rb new file mode 100644 index 0000000..bbd7651 --- /dev/null +++ b/lib/pact/generator/time.rb @@ -0,0 +1,16 @@ +require 'date' + +module Pact + module Generator + # Time provides the time generator which will give the current time in the defined format + class Time < Date + def type + 'Time' + end + + def default_format + 'HH:mm' + end + end + end +end diff --git a/lib/pact/generator/uuid.rb b/lib/pact/generator/uuid.rb new file mode 100644 index 0000000..457dcce --- /dev/null +++ b/lib/pact/generator/uuid.rb @@ -0,0 +1,19 @@ +require 'securerandom' + +module Pact + module Generator + # Uuid provides the uuid generator + class Uuid + def can_generate?(hash) + hash.key?('type') && hash['type'] == 'Uuid' + end + + # If we had the example value, we could determine what type of uuid + # to send, this is what pact-jvm does + # See https://github.com/pact-foundation/pact-jvm/blob/master/core/model/src/main/kotlin/au/com/dius/pact/core/model/generators/Generator.kt + def call(_hash, _params = nil, _example_value = nil) + SecureRandom.uuid + end + end + end +end diff --git a/lib/pact/generators.rb b/lib/pact/generators.rb new file mode 100644 index 0000000..4d41b02 --- /dev/null +++ b/lib/pact/generators.rb @@ -0,0 +1,64 @@ +require 'pact/generator/random_boolean' +require 'pact/generator/date' +require 'pact/generator/datetime' +require 'pact/generator/provider_state' +require 'pact/generator/random_decimal' +require 'pact/generator/random_hexadecimal' +require 'pact/generator/random_int' +require 'pact/generator/random_string' +require 'pact/generator/regex' +require 'pact/generator/time' +require 'pact/generator/uuid' +require 'pact/matching_rules/jsonpath' +require 'pact/matching_rules/v3/extract' +require 'jsonpath' + +module Pact + class Generators + def self.add_generator(generator) + generators.unshift(generator) + end + + def self.generators + @generators ||= [] + end + + def self.execute_generators(object, state_params = nil, example_value = nil) + generators.each do |parser| + return parser.call(object, state_params, example_value) if parser.can_generate?(object) + end + + raise Pact::UnrecognizePactFormatError, "This document does not use a recognised Pact generator: #{object}" + end + + def self.apply_generators(expected_request, component, example_value, state_params) + # Latest pact-support is required to have generators exposed + if expected_request.methods.include?(:generators) && expected_request.generators[component] + # Some component will have single generator without selectors, i.e. path + generators = expected_request.generators[component] + if generators.is_a?(Hash) && generators.key?('type') + return execute_generators(generators, state_params, example_value) + end + + generators.each do |selector, generator| + val = JsonPath.new(selector).on(example_value) + replace = execute_generators(generator, state_params, val) + example_value = JsonPath.for(example_value).gsub(selector) { |_v| replace }.to_hash + end + end + example_value + end + + add_generator(Generator::RandomBoolean.new) + add_generator(Generator::Date.new) + add_generator(Generator::DateTime.new) + add_generator(Generator::ProviderState.new) + add_generator(Generator::RandomDecimal.new) + add_generator(Generator::RandomHexadecimal.new) + add_generator(Generator::RandomInt.new) + add_generator(Generator::RandomString.new) + add_generator(Generator::Regex.new) + add_generator(Generator::Time.new) + add_generator(Generator::Uuid.new) + end +end diff --git a/pact-support.gemspec b/pact-support.gemspec index a984465..b240d6f 100644 --- a/pact-support.gemspec +++ b/pact-support.gemspec @@ -23,6 +23,8 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency "awesome_print", "~> 1.9" spec.add_runtime_dependency "diff-lcs", "~> 1.5" spec.add_runtime_dependency "expgen", "~> 0.1" + spec.add_runtime_dependency 'string_pattern', '~> 2.0' + spec.add_runtime_dependency 'jsonpath', '~> 1.0' spec.add_development_dependency "rspec", ">= 2.14", "< 4.0" spec.add_development_dependency "rake", "~> 13.0" diff --git a/spec/lib/pact/generator/date_spec.rb b/spec/lib/pact/generator/date_spec.rb new file mode 100644 index 0000000..4319d9e --- /dev/null +++ b/spec/lib/pact/generator/date_spec.rb @@ -0,0 +1,20 @@ +require 'pact/generator/date' + +describe Pact::Generator::Date do + generator = Pact::Generator::Date.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Date' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Date' } + expect(generator.call(hash).length).to eq(10) + end +end diff --git a/spec/lib/pact/generator/datetime_spec.rb b/spec/lib/pact/generator/datetime_spec.rb new file mode 100644 index 0000000..345a858 --- /dev/null +++ b/spec/lib/pact/generator/datetime_spec.rb @@ -0,0 +1,21 @@ +require 'pact/generator/datetime' + +describe Pact::Generator::DateTime do + generator = Pact::Generator::DateTime.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'DateTime' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'DateTime' } + p generator.call(hash) + expect(generator.call(hash).length).to eq(16) + end +end diff --git a/spec/lib/pact/generator/provider_state_spec.rb b/spec/lib/pact/generator/provider_state_spec.rb new file mode 100644 index 0000000..d371685 --- /dev/null +++ b/spec/lib/pact/generator/provider_state_spec.rb @@ -0,0 +1,37 @@ +require 'pact/generator/provider_state' + +describe Pact::Generator::ProviderState do + generator = Pact::Generator::ProviderState.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'ProviderState' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call without params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + expect(generator.call(hash)).to eq 'Bearer ' + end + + it 'call with correct params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'access_token' => 'ABC' } + expect(generator.call(hash, params)).to eq 'Bearer ABC' + end + + it 'call with wrong params' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'refresh_token' => 'ABC' } + expect(generator.call(hash, params)).to eq 'Bearer ' + end + + it 'call with incomplete expression' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token' } + expect { generator.call(hash) }.to raise_error('Missing closing brace in expression string') + end +end diff --git a/spec/lib/pact/generator/random_boolean_spec.rb b/spec/lib/pact/generator/random_boolean_spec.rb new file mode 100644 index 0000000..8834861 --- /dev/null +++ b/spec/lib/pact/generator/random_boolean_spec.rb @@ -0,0 +1,20 @@ +require 'pact/generator/random_boolean' + +describe Pact::Generator::RandomBoolean do + generator = Pact::Generator::RandomBoolean.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomBoolean' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomBoolean' } + expect(generator.call(hash)).to eq(true).or eq(false) + end +end diff --git a/spec/lib/pact/generator/random_decimal_spec.rb b/spec/lib/pact/generator/random_decimal_spec.rb new file mode 100644 index 0000000..4c1689f --- /dev/null +++ b/spec/lib/pact/generator/random_decimal_spec.rb @@ -0,0 +1,27 @@ +require 'pact/generator/random_decimal' + +describe Pact::Generator::RandomDecimal do + generator = Pact::Generator::RandomDecimal.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomDecimal' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomDecimal' } + value = generator.call(hash) + expect(String(value).length).to eq 7 + end + + it 'call with digits' do + hash = { 'type' => 'RandomDecimal', 'digits' => 10 } + value = generator.call(hash) + expect(String(value).length).to eq 11 + end +end diff --git a/spec/lib/pact/generator/random_hexadecimal_spec.rb b/spec/lib/pact/generator/random_hexadecimal_spec.rb new file mode 100644 index 0000000..8b124ba --- /dev/null +++ b/spec/lib/pact/generator/random_hexadecimal_spec.rb @@ -0,0 +1,25 @@ +require 'pact/generator/random_hexadecimal' + +describe Pact::Generator::RandomHexadecimal do + generator = Pact::Generator::RandomHexadecimal.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomHexadecimal' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomHexadecimal' } + expect(generator.call(hash).length).to eq(8) + end + + it 'call with size' do + hash = { 'type' => 'RandomHexadecimal', 'digits' => 2 } + expect(generator.call(hash).length).to eq(2) + end +end diff --git a/spec/lib/pact/generator/random_int_spec.rb b/spec/lib/pact/generator/random_int_spec.rb new file mode 100644 index 0000000..a2290fd --- /dev/null +++ b/spec/lib/pact/generator/random_int_spec.rb @@ -0,0 +1,25 @@ +require 'pact/generator/random_int' + +describe Pact::Generator::RandomInt do + generator = Pact::Generator::RandomInt.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomInt' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomInt' } + expect(generator.call(hash).instance_of?(Integer)).to be true + end + + it 'call with min/max' do + hash = { 'type' => 'RandomInt', 'min' => 5, 'max' => 5 } + expect(generator.call(hash)).to eq 5 + end +end diff --git a/spec/lib/pact/generator/random_string_spec.rb b/spec/lib/pact/generator/random_string_spec.rb new file mode 100644 index 0000000..8675058 --- /dev/null +++ b/spec/lib/pact/generator/random_string_spec.rb @@ -0,0 +1,25 @@ +require 'pact/generator/random_string' + +describe Pact::Generator::RandomString do + generator = Pact::Generator::RandomString.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'RandomString' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'RandomString' } + expect(generator.call(hash).length).to eq(20) + end + + it 'call with size' do + hash = { 'type' => 'RandomString', 'size' => 30 } + expect(generator.call(hash).length).to eq(30) + end +end diff --git a/spec/lib/pact/generator/regex_spec.rb b/spec/lib/pact/generator/regex_spec.rb new file mode 100644 index 0000000..723383d --- /dev/null +++ b/spec/lib/pact/generator/regex_spec.rb @@ -0,0 +1,20 @@ +require 'pact/generator/regex' + +describe Pact::Generator::Regex do + generator = Pact::Generator::Regex.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Regex' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Regex', 'pattern' => '(one|two)' } + expect(generator.call(hash)).to eq('one').or eq('two') + end +end diff --git a/spec/lib/pact/generator/time_spec.rb b/spec/lib/pact/generator/time_spec.rb new file mode 100644 index 0000000..21cd9a5 --- /dev/null +++ b/spec/lib/pact/generator/time_spec.rb @@ -0,0 +1,20 @@ +require 'pact/generator/time' + +describe Pact::Generator::Time do + generator = Pact::Generator::Time.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Time' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Time' } + expect(generator.call(hash).length).to eq(5) + end +end diff --git a/spec/lib/pact/generator/uuid_spec.rb b/spec/lib/pact/generator/uuid_spec.rb new file mode 100644 index 0000000..aa9a94d --- /dev/null +++ b/spec/lib/pact/generator/uuid_spec.rb @@ -0,0 +1,20 @@ +require 'pact/generator/uuid' + +describe Pact::Generator::Uuid do + generator = Pact::Generator::Uuid.new + + it 'can_generate with a supported hash' do + hash = { 'type' => 'Uuid' } + expect(generator.can_generate?(hash)).to be true + end + + it 'can_generate with a unsupported hash' do + hash = { 'type' => 'unknown' } + expect(generator.can_generate?(hash)).to be false + end + + it 'call' do + hash = { 'type' => 'Uuid' } + expect(generator.call(hash).length).to eq(36) + end +end diff --git a/spec/lib/pact/generators_spec.rb b/spec/lib/pact/generators_spec.rb new file mode 100644 index 0000000..5a190a5 --- /dev/null +++ b/spec/lib/pact/generators_spec.rb @@ -0,0 +1,59 @@ +require 'pact/generators' + +describe Pact::Generators do + it 'execute_generators with RandomBoolean' do + hash = { 'type' => 'RandomBoolean' } + expect(Pact::Generators.execute_generators(hash)).to eq(true).or eq(false) + end + + it 'execute_generators with Date' do + hash = { 'type' => 'Date' } + expect(Pact::Generators.execute_generators(hash).length).to eq(10) + end + + it 'execute_generators with DateTime' do + hash = { 'type' => 'DateTime' } + expect(Pact::Generators.execute_generators(hash).length).to eq(16) + end + + it 'execute_generators with ProviderState' do + hash = { 'type' => 'ProviderState', 'expression' => 'Bearer ${access_token}' } + params = { 'access_token' => 'ABC' } + expect(Pact::Generators.execute_generators(hash, params)).to eq('Bearer ABC') + end + + it 'execute_generators with RandomDecimal' do + hash = { 'type' => 'RandomDecimal' } + expect(String(Pact::Generators.execute_generators(hash)).length).to eq(7) + end + + it 'execute_generators with RandomHexadecimal' do + hash = { 'type' => 'RandomHexadecimal' } + expect(Pact::Generators.execute_generators(hash).length).to eq(8) + end + + it 'execute_generators with RandomInt' do + hash = { 'type' => 'RandomInt' } + expect(Pact::Generators.execute_generators(hash).instance_of?(Integer)).to be true + end + + it 'execute_generators with RandomString' do + hash = { 'type' => 'RandomString' } + expect(Pact::Generators.execute_generators(hash).length).to eq(20) + end + + it 'execute_generators with Regex' do + hash = { 'type' => 'Regex', 'pattern' => '(one|two)' } + expect(Pact::Generators.execute_generators(hash)).to eq('one').or eq('two') + end + + it 'execute_generators with Time' do + hash = { 'type' => 'Time' } + expect(Pact::Generators.execute_generators(hash).length).to eq(5) + end + + it 'execute_generators with Uuid' do + hash = { 'type' => 'Uuid' } + expect(Pact::Generators.execute_generators(hash).length).to eq(36) + end +end diff --git a/spec/lib/pact/matchers/matchers_provider_param_spec.rb b/spec/lib/pact/matchers/matchers_provider_param_spec.rb new file mode 100644 index 0000000..420ac36 --- /dev/null +++ b/spec/lib/pact/matchers/matchers_provider_param_spec.rb @@ -0,0 +1,19 @@ +require 'pact/from_provider_state' + +module Pact + describe Matchers do + + let(:expected) do + { + url: Pact::FromProviderState.new('/some/${url_var}/here', {url_var: 'url'}) + } + end + + it 'should not have a difference' do + actual = { + url: '/some/url/here' + } + expect(Pact::Matchers.diff(expected, actual)).to be_empty + end + end +end \ No newline at end of file diff --git a/spec/lib/pact/provider_param_spec.rb b/spec/lib/pact/provider_param_spec.rb new file mode 100644 index 0000000..99fd85b --- /dev/null +++ b/spec/lib/pact/provider_param_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +module Pact + describe FromProviderState do + describe 'initialize' do + it 'creates a FromProviderState' do + pp = FromProviderState.new('/some/url/with/${param}', { param: 'a parameter' }) + expect(pp).to be_instance_of(Pact::FromProviderState) + end + end + + describe 'default_string' do + it 'returns the default string' do + pp = FromProviderState.new('/some/url/with/${param}', { param: 'a parameter' }) + expect(pp.default_string).to eq('/some/url/with/a parameter') + end + end + + describe 'expression' do + it 'returns the expression' do + pp = FromProviderState.new('/some/${var}/here${blah}', { var: 'var', blah: 'aoeu' }) + expect(pp.expression).to eq('/some/${var}/here${blah}') + expect(pp.default_string).to eq('/some/var/hereaoeu') + end + end + + describe 'initialize with expression' do + it 'finds the param names' do + pp = FromProviderState.new('/some/${id}/path_${here}', { id: '5', here: 'something' }) + expect(pp.params).to eq({ 'id' => '5', 'here' => 'something' }) + end + + it 'finds the param names from a given default string' do + pp = FromProviderState.new('/some/${id}/path_${here}', '/some/4/path_blah') + expect(pp.params).to eq({ 'id' => '4', 'here' => 'blah' }) + end + + it 'finds the param names with a param at the start' do + pp = FromProviderState.new('${first}and${second}then${third}', 'oneandtwothenthree') + expect(pp.params).to eq({ 'first' => 'one', 'second' => 'two', 'third' => 'three' }) + end + end + end +end