Top Level Namespace

Defined Under Namespace

Modules: Boolean, Enum Classes: FalseClass, Hash, Level, ListCountComparison, ListNesting, ResponseField, String, TrueClass

Constant Summary collapse

FEWER_MORE_THAN_SYNONYM =
%q{(?:fewer|less|more) than|at (?:least|most)}
INT_AS_WORDS_SYNONYM =
%q{zero|one|two|three|four|five|six|seven|eight|nine|ten}
CMP_LESS_THAN =
'<'
CMP_MORE_THAN =
'>'
CMP_AT_LEAST =
'>='
CMP_AT_MOST =
'<='
CMP_EQUALS =
'='
HAVE_ALTERNATION =
"has/have/having/contain/contains/containing/with"
RESOURCE_NAME_SYNONYM =
'\w+\b(?:\s+\w+\b)*?|`[^`]*`'
FIELD_NAME_SYNONYM =
'\w+\b(?:(?:\s+:)?\s+\w+\b)*?|`[^`]*`'
MAXIMAL_FIELD_NAME_SYNONYM =
'\w+\b(?:(?:\s+:)?\s+\w+\b)*|`[^`]*`'
GET_TYPES =
%{(?:an?(?! list)|the)}%
WITH_ID = %{(?: with (?:key|id))? "([^"]*)"}%

Given("I am a client") do
    steps %Q{
      Given I send "application/json" and accept JSON
    }
end

Instance Method Summary collapse

Instance Method Details

#add_to_hash(a, n) ⇒ Object



151
152
153
154
155
156
157
158
159
# File 'lib/cucumber-rest-bdd/types.rb', line 151

def add_to_hash(a, n)
    result = nil    
    if (n[0] == '[' && n[-1] == ']') then
        array = Array.new(n[1..-2].to_i() + 1)
        array[n[1..-2].to_i()] = a
        result = array
    end
    result != nil ? result : { n => a };
end

#get_attributes(hashes) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/cucumber-rest-bdd/types.rb', line 126

def get_attributes(hashes)
    attributes = hashes.each_with_object({}) do |row, hash|
      name, value, type = row["attribute"], row["value"], row["type"]
      value = resolve_functions(value)
      value = resolve(value)
      value.gsub!(/\\n/, "\n")
      names = get_fields(name)
      new_hash = names.reverse.inject(string_to_type(value, type)) { |a, n| add_to_hash(a, n) }
      hash.deep_merge!(new_hash) { |key, old, new| new.kind_of?(Array) ? merge_arrays(old, new) : new }
    end
end

#get_child_data(level, data) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/cucumber-rest-bdd/data.rb', line 40

def get_child_data(level, data)
    if (level[:root]) then
        return data.dup
    else
        levelKey = case level[:type]
            when 'single' then get_field(level[:key])
            when 'multiple' then get_field(level[:key])
            when 'list' then get_resource(level[:key])
        end
        raise %/Key not found: #{level[:key]} as #{levelKey} in #{data}/ if !data[levelKey]
        return data[levelKey]
    end
end

#get_field(name) ⇒ Object



115
116
117
118
119
120
121
122
123
124
# File 'lib/cucumber-rest-bdd/types.rb', line 115

def get_field(name)
    if name[0] == '`' && name[-1] == '`'
        name = name[1..-2]
    elsif name[0] != '[' || name[-1] != ']'
        separator = ENV.has_key?('field_separator') ? ENV['field_separator'] : '_'
        name = name.parameterize(separator: separator)
        name = name.camelize(:lower) if (ENV.has_key?('field_camel') && ENV['field_camel'] == 'true')
    end
    return name
end

#get_fields(names) ⇒ Object



111
112
113
# File 'lib/cucumber-rest-bdd/types.rb', line 111

def get_fields(names)
    return names.split(':').map { |n| get_field(n.strip) }
end

#get_json_path(names) ⇒ Object



107
108
109
# File 'lib/cucumber-rest-bdd/types.rb', line 107

def get_json_path(names)
    return "#{get_root_data_key()}#{get_fields(names).join('.')}"
end

#get_key(grouping) ⇒ Object

gets the relevant key for the response based on the first key element



4
5
6
7
8
9
10
11
# File 'lib/cucumber-rest-bdd/data.rb', line 4

def get_key(grouping)
    errorKey = ENV['error_key']
    if errorKey && !errorKey.empty? && grouping.count > 1 && grouping[-2][:key].singularize == errorKey then
        return "$.#{errorKey}."
    else
        return get_root_data_key()
    end
end

#get_resource(name) ⇒ Object



93
94
95
96
97
98
99
100
101
# File 'lib/cucumber-rest-bdd/types.rb', line 93

def get_resource(name)
    if name[0] == '`' && name[-1] == '`'
        name = name[1..-2]
    else
        name = name.parameterize
        name = (ENV.has_key?('resource_single') && ENV['resource_single'] == 'true') ? name.singularize : name.pluralize
    end
    return name
end

#get_root_data_keyObject



103
104
105
# File 'lib/cucumber-rest-bdd/types.rb', line 103

def get_root_data_key()
    return ENV.has_key?('data_key') && !ENV['data_key'].empty? ? "$.#{ENV['data_key']}." : "$."
end

#get_url(path) ⇒ Object



1
2
3
4
5
6
7
# File 'lib/cucumber-rest-bdd/url.rb', line 1

def get_url(path)
    raise %/Please set an 'endpoint' environment variable provided with the url of the api/ if !ENV.has_key?('endpoint')
    url = ENV['endpoint']
    url = "#{url}/" unless url.end_with?("/")
    url = "#{url}#{@urlbasepath}/" unless @urlbasepath.to_s.empty?
    url = "#{url}#{path}" unless path.empty?
end

#merge_arrays(a, b) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/cucumber-rest-bdd/types.rb', line 161

def merge_arrays(a, b)
    new_length = [a.length, b.length].max
    new_array = Array.new(new_length)
    new_length.times do |n|
        if b[n].nil? then
            new_array[n] = a[n]
        else
            if a[n].nil? then
                new_array[n] = b[n]
            else
                new_array[n] = a[n].merge(b[n])
            end
        end
    end
    return new_array
end

#nest_match_attributes(data, nesting, expected, matchValue) ⇒ Object

top level has 2 children with an item containing at most three fish with attributes:

nesting = [key=fish,count=3,count_mod=‘<=’,type=multiple,key=item,type=single,key=children,type=multiple,count=2,count_mod=‘=’,root=true,type=single]

returns true if the expected data is contained within the data based on the nesting information



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/cucumber-rest-bdd/data.rb', line 18

def nest_match_attributes(data, nesting, expected, matchValue)
    return false if !data
    return data.deep_include?(expected) if !matchValue && nesting.size == 0
    return data.include?(expected) if matchValue && nesting.size == 0

    local_nesting = nesting.dup
    level = local_nesting.pop
    child_data = get_child_data(level, data)

    case level[:type]
        when 'single' then
            return nest_match_attributes(child_data, local_nesting, expected, matchValue)
        when 'multiple' then
            matched = child_data.select { |item| nest_match_attributes(item, local_nesting, expected, matchValue) }
            return level[:comparison].compare(matched.count)
        when 'list' then
            return child_data.is_a?(Array) && (!level.has_key?(:comparison) || level[:comparison].compare(child_data.count))
        else
            raise %/Unknown nested data type: #{level[:type]}/
    end
end

#parse_type(type) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/cucumber-rest-bdd/types.rb', line 47

def parse_type(type)
    replacements = {
        /^numeric$/i => 'numeric',
        /^int$/i => 'numeric',
        /^long$/i => 'numeric',
        /^number$/i => 'numeric',
        /^decimal$/i => 'numeric',
        /^double$/i => 'numeric',
        /^bool$/i => 'boolean',
        /^null$/i => 'nil_class',
        /^nil$/i => 'nil_class',
        /^string$/i => 'string',
        /^text$/i => 'string'
    }
    type.tr(' ', '_')
    replacements.each { |k,v| type.gsub!(k, v) }
    type
end

#resolve_functions(value) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/cucumber-rest-bdd/types.rb', line 138

def resolve_functions(value)
    value.gsub!(/\[([a-zA-Z0-9_]+)\]/) do |s|
        s.gsub!(/[\[\]]/, '')
        case s.downcase
        when "datetime"
            Time.now.strftime("%Y%m%d%H%M%S")
        else
            raise 'Unrecognised function ' + s + '?'
        end
    end
    value
end

#string_to_type(value, type) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/cucumber-rest-bdd/types.rb', line 66

def string_to_type(value, type)
    replacements = {
        /^numeric$/i => 'integer',
        /^int$/i => 'integer',
        /^long$/i => 'integer',
        /^number$/i => 'integer',
        /^decimal$/i => 'float',
        /^double$/i => 'float',
        /^bool$/i => 'boolean',
        /^null$/i => 'nil_class',
        /^nil$/i => 'nil_class',
        /^string$/i => 'string',
        /^text$/i => 'string'
    }
    type.tr(' ', '_')
    replacements.each { |k,v| type.gsub!(k, v) }
    type = type.camelize.constantize
    # cannot use 'case type' which checks for instances of a type rather than type equality
    if type == Boolean then !(value =~ /true|yes/i).nil?
    elsif type == Enum then value.upcase.tr(" ", "_")
    elsif type == Float then value.to_f
    elsif type == Integer then value.to_i
    elsif type == NilClass then nil
    else value
    end
end

#to_compare(compare) ⇒ Object

take a number modifier string (fewer than, less than, etc) and return an operator ‘<’, etc



128
129
130
131
132
133
134
135
136
137
# File 'lib/cucumber-rest-bdd/list.rb', line 128

def to_compare(compare)
    return case compare
    when 'fewer than' then CMP_LESS_THAN
    when 'less than' then CMP_LESS_THAN
    when 'more than' then CMP_MORE_THAN
    when 'at least' then CMP_AT_LEAST
    when 'at most' then CMP_AT_MOST
    else CMP_EQUALS
    end
end

#to_num(num) ⇒ Object



139
140
141
142
143
144
# File 'lib/cucumber-rest-bdd/list.rb', line 139

def to_num(num)
    if /^(?:zero|one|two|three|four|five|six|seven|eight|nine|ten)$/.match(num)
        return %w(zero one two three four five six seven eight nine ten).index(num)
    end
    return num.to_i
end