nice_hash 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +4 -4
  3. data/README.md +515 -515
  4. data/lib/nice/hash/add_to_ruby.rb +127 -127
  5. data/lib/nice_hash.rb +582 -582
  6. metadata +2 -2
@@ -1,127 +1,127 @@
1
- class Array
2
-
3
- ###########################################################################
4
- # Stores a value on the location indicated
5
- # input:
6
- # where: (Array)
7
- # value
8
- # examples:
9
- # my_array.bury([3, 0], "doom") # array of array
10
- # my_array.bury([2, 1, :original],"the value to set") #array of array of hash
11
- ###########################################################################
12
- def bury(where, value)
13
- me=self
14
- where[0..-2].each {|key|
15
- me=me[key]
16
- }
17
- me[where[-1]]=value
18
- end
19
- end
20
-
21
-
22
- class Hash
23
- ###########################################################################
24
- # Returns the value of the key specified in case doesn't exist a Hash method with the same name
25
- # The keys can be accessed also adding underscore to avoid problems with existent methods
26
- # Also set values in case = supplied
27
- # examples:
28
- # my_hash.address.correct
29
- # my_hash._address._correct
30
- # my_hash.city
31
- # my_hash._city
32
- # my_hash.city="Paris"
33
- # my_hash.products[1].price.wrong="AAAAA"
34
- ###########################################################################
35
- def method_missing(m, *arguments, &block)
36
- if m[0]=='_'
37
- m=m[1..-1].to_sym
38
- end
39
- if self.keys.include?(m)
40
- self[m]
41
- elsif m.to_s[-1]=="="
42
- self[m.to_s.chop.to_sym]=arguments[0]
43
- else
44
- super
45
- end
46
- end
47
-
48
- ###########################################################################
49
- # Stores a value on the location indicated
50
- # input:
51
- # where: (Array)
52
- # value
53
- # examples:
54
- # my_hash.bury([:bip, :doom], "doom") # hash of hash
55
- # my_hash.bury([:original, 1, :doom],"the value to set") #hash of array of hash
56
- ###########################################################################
57
- def bury(where, value)
58
- me=self
59
- where[0..-2].each {|key|
60
- me=me[key]
61
- }
62
- key=where[-1]
63
- key=[key] unless where[-1].kind_of?(Array) # for the case same value for different keys, for example pwd1, pwd2, pwd3
64
- key.each {|k|
65
- me[k]=value
66
- }
67
- end
68
-
69
- ###########################################################################
70
- # It will filter the hash by the key specified on select_hash_key.
71
- # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
72
- # More info: NiceHash.select_key
73
- ###########################################################################
74
- def select_key(select_hash_key)
75
- NiceHash.select_key(self, select_hash_key)
76
- end
77
-
78
- ###########################################################################
79
- # It will generate a new hash with the values generated from the string patterns and select fields specified.
80
- # In case supplied select_hash_key and a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
81
- # If expected_errors specified the values will be generated with the specified errors.
82
- # More info: NiceHash.generate
83
- # alias: gen
84
- ###########################################################################
85
- def generate(select_hash_key=nil, expected_errors: [], **synonyms)
86
- NiceHash.generate(self, select_hash_key, expected_errors: expected_errors, **synonyms)
87
- end
88
-
89
- ###########################################################################
90
- # Validates a given values_hash_to_validate with string patterns and select fields
91
- # More info: NiceHash.validate
92
- # alias: val
93
- ###########################################################################
94
- def validate(select_hash_key=nil, values_hash_to_validate)
95
- NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: false)
96
- end
97
-
98
- ###########################################################################
99
- # Validates a given values_hash_to_validate with string patterns
100
- # More info: NiceHash.validate
101
- ###########################################################################
102
- def validate_patterns(select_hash_key=nil, values_hash_to_validate)
103
- NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: true)
104
- end
105
-
106
- ###########################################################################
107
- # It will return an array of the keys where we are using string patterns.
108
- # More info: NiceHash.pattern_fields
109
- ###########################################################################
110
- def pattern_fields(*select_hash_key)
111
- NiceHash.pattern_fields(self, *select_hash_key)
112
- end
113
-
114
- ###########################################################################
115
- # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
116
- # More info: NiceHash.select_fields
117
- ###########################################################################
118
- def select_fields(*select_hash_key)
119
- NiceHash.select_fields(self, *select_hash_key)
120
- end
121
-
122
-
123
- alias_method :gen, :generate
124
- alias_method :val, :validate
125
- alias_method :patterns, :pattern_fields
126
-
127
- end
1
+ class Array
2
+
3
+ ###########################################################################
4
+ # Stores a value on the location indicated
5
+ # input:
6
+ # where: (Array)
7
+ # value
8
+ # examples:
9
+ # my_array.bury([3, 0], "doom") # array of array
10
+ # my_array.bury([2, 1, :original],"the value to set") #array of array of hash
11
+ ###########################################################################
12
+ def bury(where, value)
13
+ me=self
14
+ where[0..-2].each {|key|
15
+ me=me[key]
16
+ }
17
+ me[where[-1]]=value
18
+ end
19
+ end
20
+
21
+
22
+ class Hash
23
+ ###########################################################################
24
+ # Returns the value of the key specified in case doesn't exist a Hash method with the same name
25
+ # The keys can be accessed also adding underscore to avoid problems with existent methods
26
+ # Also set values in case = supplied
27
+ # examples:
28
+ # my_hash.address.correct
29
+ # my_hash._address._correct
30
+ # my_hash.city
31
+ # my_hash._city
32
+ # my_hash.city="Paris"
33
+ # my_hash.products[1].price.wrong="AAAAA"
34
+ ###########################################################################
35
+ def method_missing(m, *arguments, &block)
36
+ if m[0]=='_'
37
+ m=m[1..-1].to_sym
38
+ end
39
+ if self.keys.include?(m)
40
+ self[m]
41
+ elsif m.to_s[-1]=="="
42
+ self[m.to_s.chop.to_sym]=arguments[0]
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ ###########################################################################
49
+ # Stores a value on the location indicated
50
+ # input:
51
+ # where: (Array)
52
+ # value
53
+ # examples:
54
+ # my_hash.bury([:bip, :doom], "doom") # hash of hash
55
+ # my_hash.bury([:original, 1, :doom],"the value to set") #hash of array of hash
56
+ ###########################################################################
57
+ def bury(where, value)
58
+ me=self
59
+ where[0..-2].each {|key|
60
+ me=me[key]
61
+ }
62
+ key=where[-1]
63
+ key=[key] unless where[-1].kind_of?(Array) # for the case same value for different keys, for example pwd1, pwd2, pwd3
64
+ key.each {|k|
65
+ me[k]=value
66
+ }
67
+ end
68
+
69
+ ###########################################################################
70
+ # It will filter the hash by the key specified on select_hash_key.
71
+ # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
72
+ # More info: NiceHash.select_key
73
+ ###########################################################################
74
+ def select_key(select_hash_key)
75
+ NiceHash.select_key(self, select_hash_key)
76
+ end
77
+
78
+ ###########################################################################
79
+ # It will generate a new hash with the values generated from the string patterns and select fields specified.
80
+ # In case supplied select_hash_key and a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
81
+ # If expected_errors specified the values will be generated with the specified errors.
82
+ # More info: NiceHash.generate
83
+ # alias: gen
84
+ ###########################################################################
85
+ def generate(select_hash_key=nil, expected_errors: [], **synonyms)
86
+ NiceHash.generate(self, select_hash_key, expected_errors: expected_errors, **synonyms)
87
+ end
88
+
89
+ ###########################################################################
90
+ # Validates a given values_hash_to_validate with string patterns and select fields
91
+ # More info: NiceHash.validate
92
+ # alias: val
93
+ ###########################################################################
94
+ def validate(select_hash_key=nil, values_hash_to_validate)
95
+ NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: false)
96
+ end
97
+
98
+ ###########################################################################
99
+ # Validates a given values_hash_to_validate with string patterns
100
+ # More info: NiceHash.validate
101
+ ###########################################################################
102
+ def validate_patterns(select_hash_key=nil, values_hash_to_validate)
103
+ NiceHash.validate([self, select_hash_key], values_hash_to_validate, only_patterns: true)
104
+ end
105
+
106
+ ###########################################################################
107
+ # It will return an array of the keys where we are using string patterns.
108
+ # More info: NiceHash.pattern_fields
109
+ ###########################################################################
110
+ def pattern_fields(*select_hash_key)
111
+ NiceHash.pattern_fields(self, *select_hash_key)
112
+ end
113
+
114
+ ###########################################################################
115
+ # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
116
+ # More info: NiceHash.select_fields
117
+ ###########################################################################
118
+ def select_fields(*select_hash_key)
119
+ NiceHash.select_fields(self, *select_hash_key)
120
+ end
121
+
122
+
123
+ alias_method :gen, :generate
124
+ alias_method :val, :validate
125
+ alias_method :patterns, :pattern_fields
126
+
127
+ end
@@ -1,582 +1,582 @@
1
- SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
2
- require_relative 'nice/hash/add_to_ruby' if SP_ADD_TO_RUBY
3
-
4
- require 'string_pattern'
5
-
6
- ###########################################################################
7
- # NiceHash creates hashes following certain patterns so your testing will be much easier.
8
- # You can easily generates all the hashes you want following the criteria you specify.
9
- # Many other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key.
10
- # You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.
11
- # To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern
12
- # This is the Hash we will be using on the examples declared on the methods source code documentation:
13
- # my_hash={
14
- # name: 'Peter',
15
- # address: {wrong: '#$$$$$', correct: :'10-30:L_'},
16
- # city: {wrong: 'Germany', correct: :'Madrid|Barcelona|London|Akureyri'},
17
- # products: [
18
- # {
19
- # name: :'10:Ln',
20
- # price: {wrong: '-20', correct: :'1-10:N'}
21
- # },
22
- # {
23
- # name: :'10:Ln',
24
- # price: {wrong: '-20', correct: :'1-10:N'}
25
- # },
26
- # ]
27
- # }
28
- ###########################################################################
29
- class NiceHash
30
-
31
- ###########################################################################
32
- # It will filter the hash by the key specified on select_hash_key.
33
- # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
34
- #
35
- # input:
36
- # pattern_hash: (Hash) Hash we want to select specific keys
37
- # select_hash_key: (key value) The key we want to select on the subhashes
38
- # output: (Hash)
39
- # The same hash but in case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
40
- # example:
41
- # new_hash = NiceHash.select_key(my_hash, :wrong)
42
- # #> {:name=>"Peter", :address=>"\#$$$$$", :city=>"Germany", :products=> [{:name=>:"10:Ln", :price=>"-20"}, {:name=>:"10:Ln", :price=>"-20"}]}
43
- # Using it directly on Hash class, select_key(select_hash_key):
44
- # new_hash = my_hash.select_key(:wrong)
45
- ###########################################################################
46
- def NiceHash.select_key(pattern_hash, select_hash_key)
47
- hash=Hash.new()
48
-
49
- if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
50
- pattern_hash.each {|key, value|
51
-
52
- if value.kind_of?(Hash)
53
- if value.keys.include?(select_hash_key)
54
- value=value[select_hash_key]
55
- else
56
- value=NiceHash.select_key(value, select_hash_key)
57
- end
58
- end
59
- if value.kind_of?(Array)
60
- array_pattern=false
61
- value.each {|v|
62
- if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
63
- hash[key]=value
64
- array_pattern=true
65
- break
66
- end
67
- }
68
- unless array_pattern
69
- value_ret=Array.new
70
- value.each {|v|
71
- ret=NiceHash.select_key(v, select_hash_key)
72
- value_ret<<ret
73
- }
74
- hash[key]=value_ret
75
- end
76
- else
77
- hash[key]=value
78
- end
79
- }
80
- else
81
- return pattern_hash
82
- end
83
- return hash
84
- end
85
-
86
- ###########################################################################
87
- # It will return an array of the keys where we are using string patterns.
88
- #
89
- # input:
90
- # pattern_hash: (Hash) Hash we want to get the pattern_fields
91
- # select_hash_key: (key value) (optional) The key we want to select on the subhashes
92
- # output: (Array)
93
- # Array of the kind: [ [key], [key, subkey, subkey] ]
94
- # Each value of the array can be used as parameter for the methods: dig, bury
95
- # examples:
96
- # NiceHash.pattern_fields(my_hash)
97
- # #> [
98
- # [:address, :correct],
99
- # [:products, 0, :name],
100
- # [:products, 0, :price, :correct],
101
- # [:products, 1, :name],
102
- # [:products, 1, :price, :correct]
103
- # ]
104
- # NiceHash.pattern_fields(my_hash, :correct)
105
- # #> [
106
- # [:address],
107
- # [:products, 0, :name],
108
- # [:products, 0, :price],
109
- # [:products, 1, :name],
110
- # [:products, 1, :price]
111
- # ]
112
- # Using it directly on Hash class, pattern_fields(*select_hash_key) (alias: patterns):
113
- # my_hash.pattern_fields
114
- # my_hash.pattern_fields(:correct)
115
- # my_hash.patterns(:correct)
116
- ###########################################################################
117
- def NiceHash.pattern_fields(pattern_hash, *select_hash_key)
118
- pattern_fields = Array.new
119
-
120
- if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
121
- pattern_hash.each {|key, value|
122
- key=[key]
123
- if value.kind_of?(Hash)
124
- if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
125
- value=value[select_hash_key[0]]
126
- else
127
- res=NiceHash.pattern_fields(value, *select_hash_key)
128
- if res.size>0
129
- res.each {|r|
130
- pattern_fields<<(r.unshift(key)).flatten
131
- }
132
- end
133
- next
134
- end
135
- end
136
- if value.kind_of?(String)
137
- if StringPattern.optimistic and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
138
- pattern_fields << key
139
- end
140
- elsif value.kind_of?(Symbol)
141
- if value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
142
- pattern_fields << key
143
- end
144
- elsif value.kind_of?(Array)
145
-
146
- array_pattern=false
147
- value.each {|v|
148
- if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
149
- pattern_fields << key
150
- array_pattern=true
151
- break
152
- end
153
- }
154
- unless array_pattern
155
- i=0
156
- value.each {|v|
157
- res=NiceHash.pattern_fields(v, *select_hash_key)
158
- if res.size>0
159
- res.each {|r|
160
- pattern_fields<<(r.unshift(i).unshift(key)).flatten
161
- }
162
- end
163
- i+=1
164
- }
165
- end
166
- end
167
- }
168
- end
169
-
170
- return pattern_fields
171
- end
172
-
173
- ###########################################################################
174
- # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
175
- #
176
- # input:
177
- # pattern_hash: (Hash) Hash we want to get the select_fields
178
- # select_hash_key: (key value) (optional) The key we want to select on the subhashes
179
- # output: (Array)
180
- # Array of the kind: [ [key], [key, subkey, subkey] ]
181
- # Each value of the array can be used as parameter for the methods: dig, bury
182
- # examples:
183
- # NiceHash.select_fields(my_hash)
184
- # #> [[:city, :correct]]
185
- # NiceHash.select_fields(my_hash, :correct)
186
- # #> [[:city]]
187
- # Using it directly on Hash class, select_fields(*select_hash_key):
188
- # my_hash.select_fields
189
- # my_hash.select_fields(:correct)
190
- ###########################################################################
191
- def NiceHash.select_fields(pattern_hash, *select_hash_key)
192
- select_fields = Array.new
193
-
194
- if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
195
- pattern_hash.each {|key, value|
196
- key=[key]
197
- if value.kind_of?(Hash)
198
- if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
199
- value=value[select_hash_key[0]]
200
- else
201
- res=NiceHash.select_fields(value, *select_hash_key)
202
- if res.size>0
203
- res.each {|r|
204
- select_fields<<(r.unshift(key)).flatten
205
- }
206
- end
207
- next
208
- end
209
- end
210
- if value.kind_of?(String)
211
- if StringPattern.optimistic and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
212
- select_fields << key
213
- end
214
- elsif value.kind_of?(Symbol)
215
- if value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
216
- select_fields << key
217
- end
218
- elsif value.kind_of?(Array)
219
-
220
- array_pattern=false
221
- value.each {|v|
222
- if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
223
- array_pattern=true
224
- break
225
- end
226
- }
227
- unless array_pattern
228
- i=0
229
- value.each {|v|
230
- res=NiceHash.select_fields(v, *select_hash_key)
231
- if res.size>0
232
- res.each {|r|
233
- select_fields<<(r.unshift(i).unshift(key)).flatten
234
- }
235
- end
236
- i+=1
237
- }
238
- end
239
- end
240
- }
241
- end
242
-
243
- return select_fields
244
- end
245
-
246
-
247
- ###########################################################################
248
- # It will generate a new hash with the values generated from the string patterns and select fields specified.
249
- # In case supplied select_hash_key and a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
250
- # If expected_errors specified the values will be generated with the specified errors.
251
- # input:
252
- # pattern_hash: (Hash) Hash we want to use to generate the values
253
- # select_hash_key: (key value) (optional) The key we want to select on the subhashes
254
- # expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
255
- # The possible values you can specify is one or more of these ones:
256
- # :length: wrong length, minimum or maximum
257
- # :min_length: wrong minimum length
258
- # :max_length: wrong maximum length
259
- # :value: wrong resultant value
260
- # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
261
- # :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
262
- # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
263
- # output: (Hash)
264
- # The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
265
- # examples:
266
- # new_hash = NiceHash.generate(my_hash)
267
- # #> {:name=>"Peter",
268
- # :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
269
- # :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
270
- # :products=> [
271
- # {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
272
- # {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
273
- # ]
274
- # }
275
- # new_hash = NiceHash.generate(my_hash, :correct)
276
- # #> {:name=>"Peter",
277
- # :address=>"juQeAVZjIuWBPsE",
278
- # :city=>"Madrid",
279
- # :products=> [
280
- # {:name=>"G44Ilr0puV", :price=>"477813"},
281
- # {:name=>"v6ojs79LOp", :price=>"74820"}
282
- # ]
283
- # }
284
- # new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
285
- # #> {:name=>"Peter",
286
- # :address=>"ZytjefJ",
287
- # :city=>"Madri",
288
- # :products=>[
289
- # {:name=>"cIBrzeO", :price=>""},
290
- # {:name=>"5", :price=>""}
291
- # ]
292
- # }
293
- # Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
294
- # new_hash = my_hash.generate
295
- # new_hash = my_hash.gen(:correct)
296
- # new_hash = my_hash.generate(:correct, errors: [:min_length])
297
- ###########################################################################
298
- def NiceHash.generate(pattern_hash, select_hash_key=nil, expected_errors: [], **synonyms)
299
- hash=Hash.new()
300
- same_values=Hash.new()
301
- expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
302
- if expected_errors.kind_of?(Symbol)
303
- expected_errors=[expected_errors]
304
- end
305
-
306
- if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
307
- pattern_hash.each {|key, value|
308
-
309
- if key.kind_of?(Array)
310
- same_values[key[0]]=key.dup
311
- same_values[key[0]].shift
312
- key=key[0]
313
- end
314
- if value.kind_of?(Hash)
315
- if value.keys.include?(select_hash_key)
316
- value=value[select_hash_key]
317
- else
318
- value=NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
319
- end
320
- end
321
-
322
- if value.kind_of?(String) or value.kind_of?(Symbol)
323
- if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
324
- hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
325
- elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
326
- if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round==0)
327
- min=value.to_s.split("|").min {|a, b| a.size <=> b.size}
328
- hash[key]=min[0..-2] unless min==""
329
- end
330
- if !hash.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
331
- max=value.to_s.split("|").max {|a, b| a.size <=> b.size}
332
- hash[key]=max+max[-1]
333
- end
334
- if expected_errors.include?(:value) or
335
- expected_errors.include?(:string_set_not_allowed) or
336
- expected_errors.include?(:required_data)
337
- if hash.keys.include?(key)
338
- v=hash[key]
339
- else
340
- v=value.to_s.split("|").sample
341
- end
342
- unless expected_errors.include?(:string_set_not_allowed)
343
- v=StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
344
- hash[key]=v unless value.to_s.split("|").include?(v)
345
- end
346
- unless hash.keys.include?(key)
347
- one_wrong_letter=StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
348
- v[rand(v.size)]=one_wrong_letter
349
- hash[key]=v unless value.to_s.split("|").include?(v)
350
- end
351
- end
352
- unless hash.keys.include?(key)
353
- hash[key]=value.to_s.split("|").sample
354
- end
355
- else
356
- hash[key]=value
357
- end
358
- elsif value.kind_of?(Array)
359
- array_pattern=false
360
- value.each {|v|
361
- if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
362
- hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
363
- array_pattern=true
364
- break
365
- end
366
- }
367
- unless array_pattern
368
- value_ret=Array.new
369
- value.each {|v|
370
- ret=NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
371
- ret=v if ret.kind_of?(Hash) and ret.size==0
372
- value_ret<<ret
373
- }
374
- hash[key]=value_ret
375
- end
376
- else
377
- hash[key]=value
378
- end
379
-
380
- if same_values.include?(key)
381
- same_values[key].each {|k|
382
- hash[k]=hash[key]
383
- }
384
- end
385
-
386
- }
387
- end
388
-
389
- return hash
390
- end
391
-
392
-
393
- ###########################################################################
394
- # Validates a given values_hash_to_validate with string patterns and select fields from pattern_hash
395
- # input:
396
- # patterns_hash:
397
- # (Hash) Hash where we have defined the patterns to follow.
398
- # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
399
- # values_hash_to_validate: (Hash) Hash of values to validate
400
- # only_patterns: (TrueFalse) (by default true) If true it will validate only the patterns and not the other fields
401
- # output: (Hash)
402
- # A hash with the validation results. It will return only the validation errors so in case no validation errors found, empty hash.
403
- # The keys of the hash will be the keys of the values hash with the validation error.
404
- # The value in case of a pattern, will be an array with one or more of these possibilities:
405
- # :length: wrong length, minimum or maximum
406
- # :min_length: wrong minimum length
407
- # :max_length: wrong maximum length
408
- # :value: wrong resultant value
409
- # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
410
- # :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
411
- # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
412
- # The value in any other case it will be false if the value is not corresponding to the expected.
413
- # examples:
414
- # values_to_validate = {:name=>"Peter",
415
- # :address=>"fnMuKW",
416
- # :city=>"Dublin",
417
- # :products=>[{:name=>"V4", :price=>"344"}, {:name=>"E", :price=>"a"}]
418
- # }
419
- # results = NiceHash.validate([my_hash, :correct], values_to_validate)
420
- # #> {:address=>[:min_length, :length],
421
- # :products=> [{:name=>[:min_length, :length]},
422
- # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
423
- # ]
424
- # }
425
- # results = NiceHash.validate([my_hash, :correct], values_to_validate, only_patterns: false)
426
- # #> {:address=>[:min_length, :length],
427
- # :city=>false,
428
- # :products=> [{:name=>[:min_length, :length]},
429
- # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
430
- # ]
431
- # }
432
- # Using it directly on Hash class:
433
- # validate(select_hash_key=nil, values_hash_to_validate) (alias: val)
434
- # validate_patterns(select_hash_key=nil, values_hash_to_validate)
435
- #
436
- # results = my_hash.validate_patterns(:correct, values_to_validate)
437
- # results = my_hash.validate(:correct, values_to_validate)
438
- ###########################################################################
439
- def NiceHash.validate(patterns_hash, values_hash_to_validate, only_patterns: true)
440
- if patterns_hash.kind_of?(Array)
441
- pattern_hash=patterns_hash[0]
442
- select_hash_key=patterns_hash[1]
443
- elsif patterns_hash.kind_of?(Hash)
444
- pattern_hash=patterns_hash
445
- select_hash_key=nil
446
- else
447
- puts "NiceHash.validate wrong pattern_hash supplied #{patterns_hash.inspect}"
448
- return {error: :error}
449
- end
450
- values = values_hash_to_validate
451
- results={}
452
- same_values={}
453
- if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
454
- pattern_hash.each {|key, value|
455
-
456
- if key.kind_of?(Array)
457
- same_values[key[0]]=key.dup
458
- same_values[key[0]].shift
459
- key=key[0]
460
- end
461
- if value.kind_of?(Hash)
462
- if !select_hash_key.nil? and value.keys.include?(select_hash_key)
463
- value=value[select_hash_key]
464
- elsif values.keys.include?(key) and values[key].kind_of?(Hash)
465
- res=NiceHash.validate([value, select_hash_key], values[key], only_patterns: only_patterns)
466
- results[key]=res if res.size>0
467
- next
468
- end
469
- end
470
-
471
- if values.keys.include?(key)
472
- if value.kind_of?(String) or value.kind_of?(Symbol)
473
- if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
474
- res=StringPattern.validate(pattern: value, text: values[key])
475
- results[key]=res if res.size>0
476
- elsif !only_patterns and ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
477
- results[key]=false unless value.to_s.split("|").include?(values[key])
478
- elsif !only_patterns
479
- results[key]=false unless value.to_s==values[key].to_s
480
- end
481
- elsif value.kind_of?(Array)
482
- array_pattern=false
483
- complex_data=false
484
- value.each {|v|
485
- if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
486
- res=StringPattern.validate(pattern: value, text: values[key])
487
- results[key]=res if res==false
488
- array_pattern=true
489
- break
490
- elsif v.kind_of?(Hash) or v.kind_of?(Array) or v.kind_of?(Struct)
491
- complex_data=true
492
- break
493
- end
494
- }
495
- unless array_pattern or results.include?(key)
496
- i=0
497
- value.each {|v|
498
- res=NiceHash.validate([v, select_hash_key], values[key][i], only_patterns: only_patterns)
499
- if res.size>0
500
- results[key]=Array.new() if !results.keys.include?(key)
501
- results[key][i]=res
502
- end
503
- i+=1
504
- }
505
-
506
- end
507
- unless array_pattern or only_patterns or results.include?(key) or complex_data
508
- results[key]=false unless value==values[key]
509
- end
510
-
511
- else
512
- unless only_patterns
513
- results[key]=false unless value==values[key]
514
- end
515
- end
516
-
517
- if same_values.include?(key)
518
- same_values[key].each {|k|
519
- if values.keys.include?(k)
520
- if values[key]!=values[k]
521
- results[k]="Not equal to #{key}"
522
- end
523
- end
524
- }
525
- end
526
-
527
- end
528
- }
529
-
530
- end
531
-
532
- return results
533
- end
534
-
535
- ###########################################################################
536
- # Change only one value at a time and return an Array of Hashes
537
- # Let's guess we need to test a typical registration REST service and the service has many fields with many validations but we want to test it one field at a time.
538
- # This method generates values following the patterns on patterns_hash and generates a new hash for every pattern/select field found on patterns_hash using the value supplied on values_hash
539
- # input:
540
- # patterns_hash:
541
- # (Hash) Hash where we have defined the patterns to follow.
542
- # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
543
- # values_hash: (Hash) Hash of values to use to modify the values generated on patterns_hash
544
- # output: (Array of Hashes)
545
- # example:
546
- # wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
547
- # array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
548
- # array_of_hashes.each {|hash_with_one_wrong_field|
549
- # #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
550
- # #if you want to know which field is the one that is wrong:
551
- # res = my_hash.validate(:correct, hash_with_one_wrong_field)
552
- # }
553
- ###########################################################################
554
- def NiceHash.change_one_by_one(patterns_hash, values_hash)
555
- if patterns_hash.kind_of?(Array)
556
- select_key=patterns_hash[1]
557
- pattern_hash=patterns_hash[0]
558
- else
559
- pattern_hash=patterns_hash
560
- select_key=[]
561
- end
562
- array=Array.new
563
- good_values=NiceHash.generate(pattern_hash, select_key)
564
- select_keys=pattern_hash.pattern_fields(select_key)+pattern_hash.select_fields(select_key)
565
- select_keys.each {|field|
566
- new_hash=Marshal.load(Marshal.dump(good_values))
567
- # to deal with the case same values... like in pwd1, pwd2, pwd3
568
- if field[-1].kind_of?(Array)
569
- last_to_set=field[-1]
570
- else
571
- last_to_set=[field[-1]]
572
- end
573
- last_to_set.each {|f|
574
- keys=field[0..-2]<<f
575
- new_hash.bury(keys, values_hash.dig(*keys))
576
- }
577
- array<<new_hash
578
- }
579
- return array
580
- end
581
-
582
- end
1
+ SP_ADD_TO_RUBY = true if !defined?(SP_ADD_TO_RUBY)
2
+ require_relative 'nice/hash/add_to_ruby' if SP_ADD_TO_RUBY
3
+
4
+ require 'string_pattern'
5
+
6
+ ###########################################################################
7
+ # NiceHash creates hashes following certain patterns so your testing will be much easier.
8
+ # You can easily generates all the hashes you want following the criteria you specify.
9
+ # Many other features coming to Hash class like the methods 'bury' or select_key, access the keys like methods: my_hash.my_key.other_key.
10
+ # You will be able to generate thousands of different hashes just declaring one and test easily APIs based on JSON for example.
11
+ # To generate the strings following a pattern take a look at the documentation for string_pattern gem: https://github.com/MarioRuiz/string_pattern
12
+ # This is the Hash we will be using on the examples declared on the methods source code documentation:
13
+ # my_hash={
14
+ # name: 'Peter',
15
+ # address: {wrong: '#$$$$$', correct: :'10-30:L_'},
16
+ # city: {wrong: 'Germany', correct: :'Madrid|Barcelona|London|Akureyri'},
17
+ # products: [
18
+ # {
19
+ # name: :'10:Ln',
20
+ # price: {wrong: '-20', correct: :'1-10:N'}
21
+ # },
22
+ # {
23
+ # name: :'10:Ln',
24
+ # price: {wrong: '-20', correct: :'1-10:N'}
25
+ # },
26
+ # ]
27
+ # }
28
+ ###########################################################################
29
+ class NiceHash
30
+
31
+ ###########################################################################
32
+ # It will filter the hash by the key specified on select_hash_key.
33
+ # In case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
34
+ #
35
+ # input:
36
+ # pattern_hash: (Hash) Hash we want to select specific keys
37
+ # select_hash_key: (key value) The key we want to select on the subhashes
38
+ # output: (Hash)
39
+ # The same hash but in case a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
40
+ # example:
41
+ # new_hash = NiceHash.select_key(my_hash, :wrong)
42
+ # #> {:name=>"Peter", :address=>"\#$$$$$", :city=>"Germany", :products=> [{:name=>:"10:Ln", :price=>"-20"}, {:name=>:"10:Ln", :price=>"-20"}]}
43
+ # Using it directly on Hash class, select_key(select_hash_key):
44
+ # new_hash = my_hash.select_key(:wrong)
45
+ ###########################################################################
46
+ def NiceHash.select_key(pattern_hash, select_hash_key)
47
+ hash=Hash.new()
48
+
49
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
50
+ pattern_hash.each {|key, value|
51
+
52
+ if value.kind_of?(Hash)
53
+ if value.keys.include?(select_hash_key)
54
+ value=value[select_hash_key]
55
+ else
56
+ value=NiceHash.select_key(value, select_hash_key)
57
+ end
58
+ end
59
+ if value.kind_of?(Array)
60
+ array_pattern=false
61
+ value.each {|v|
62
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
63
+ hash[key]=value
64
+ array_pattern=true
65
+ break
66
+ end
67
+ }
68
+ unless array_pattern
69
+ value_ret=Array.new
70
+ value.each {|v|
71
+ ret=NiceHash.select_key(v, select_hash_key)
72
+ value_ret<<ret
73
+ }
74
+ hash[key]=value_ret
75
+ end
76
+ else
77
+ hash[key]=value
78
+ end
79
+ }
80
+ else
81
+ return pattern_hash
82
+ end
83
+ return hash
84
+ end
85
+
86
+ ###########################################################################
87
+ # It will return an array of the keys where we are using string patterns.
88
+ #
89
+ # input:
90
+ # pattern_hash: (Hash) Hash we want to get the pattern_fields
91
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
92
+ # output: (Array)
93
+ # Array of the kind: [ [key], [key, subkey, subkey] ]
94
+ # Each value of the array can be used as parameter for the methods: dig, bury
95
+ # examples:
96
+ # NiceHash.pattern_fields(my_hash)
97
+ # #> [
98
+ # [:address, :correct],
99
+ # [:products, 0, :name],
100
+ # [:products, 0, :price, :correct],
101
+ # [:products, 1, :name],
102
+ # [:products, 1, :price, :correct]
103
+ # ]
104
+ # NiceHash.pattern_fields(my_hash, :correct)
105
+ # #> [
106
+ # [:address],
107
+ # [:products, 0, :name],
108
+ # [:products, 0, :price],
109
+ # [:products, 1, :name],
110
+ # [:products, 1, :price]
111
+ # ]
112
+ # Using it directly on Hash class, pattern_fields(*select_hash_key) (alias: patterns):
113
+ # my_hash.pattern_fields
114
+ # my_hash.pattern_fields(:correct)
115
+ # my_hash.patterns(:correct)
116
+ ###########################################################################
117
+ def NiceHash.pattern_fields(pattern_hash, *select_hash_key)
118
+ pattern_fields = Array.new
119
+
120
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
121
+ pattern_hash.each {|key, value|
122
+ key=[key]
123
+ if value.kind_of?(Hash)
124
+ if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
125
+ value=value[select_hash_key[0]]
126
+ else
127
+ res=NiceHash.pattern_fields(value, *select_hash_key)
128
+ if res.size>0
129
+ res.each {|r|
130
+ pattern_fields<<(r.unshift(key)).flatten
131
+ }
132
+ end
133
+ next
134
+ end
135
+ end
136
+ if value.kind_of?(String)
137
+ if StringPattern.optimistic and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
138
+ pattern_fields << key
139
+ end
140
+ elsif value.kind_of?(Symbol)
141
+ if value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
142
+ pattern_fields << key
143
+ end
144
+ elsif value.kind_of?(Array)
145
+
146
+ array_pattern=false
147
+ value.each {|v|
148
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
149
+ pattern_fields << key
150
+ array_pattern=true
151
+ break
152
+ end
153
+ }
154
+ unless array_pattern
155
+ i=0
156
+ value.each {|v|
157
+ res=NiceHash.pattern_fields(v, *select_hash_key)
158
+ if res.size>0
159
+ res.each {|r|
160
+ pattern_fields<<(r.unshift(i).unshift(key)).flatten
161
+ }
162
+ end
163
+ i+=1
164
+ }
165
+ end
166
+ end
167
+ }
168
+ end
169
+
170
+ return pattern_fields
171
+ end
172
+
173
+ ###########################################################################
174
+ # It will return an array of the keys where we are using select values of the kind: "value1|value2|value3".
175
+ #
176
+ # input:
177
+ # pattern_hash: (Hash) Hash we want to get the select_fields
178
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
179
+ # output: (Array)
180
+ # Array of the kind: [ [key], [key, subkey, subkey] ]
181
+ # Each value of the array can be used as parameter for the methods: dig, bury
182
+ # examples:
183
+ # NiceHash.select_fields(my_hash)
184
+ # #> [[:city, :correct]]
185
+ # NiceHash.select_fields(my_hash, :correct)
186
+ # #> [[:city]]
187
+ # Using it directly on Hash class, select_fields(*select_hash_key):
188
+ # my_hash.select_fields
189
+ # my_hash.select_fields(:correct)
190
+ ###########################################################################
191
+ def NiceHash.select_fields(pattern_hash, *select_hash_key)
192
+ select_fields = Array.new
193
+
194
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
195
+ pattern_hash.each {|key, value|
196
+ key=[key]
197
+ if value.kind_of?(Hash)
198
+ if select_hash_key.size==1 and value.keys.include?(select_hash_key[0])
199
+ value=value[select_hash_key[0]]
200
+ else
201
+ res=NiceHash.select_fields(value, *select_hash_key)
202
+ if res.size>0
203
+ res.each {|r|
204
+ select_fields<<(r.unshift(key)).flatten
205
+ }
206
+ end
207
+ next
208
+ end
209
+ end
210
+ if value.kind_of?(String)
211
+ if StringPattern.optimistic and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
212
+ select_fields << key
213
+ end
214
+ elsif value.kind_of?(Symbol)
215
+ if value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
216
+ select_fields << key
217
+ end
218
+ elsif value.kind_of?(Array)
219
+
220
+ array_pattern=false
221
+ value.each {|v|
222
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
223
+ array_pattern=true
224
+ break
225
+ end
226
+ }
227
+ unless array_pattern
228
+ i=0
229
+ value.each {|v|
230
+ res=NiceHash.select_fields(v, *select_hash_key)
231
+ if res.size>0
232
+ res.each {|r|
233
+ select_fields<<(r.unshift(i).unshift(key)).flatten
234
+ }
235
+ end
236
+ i+=1
237
+ }
238
+ end
239
+ end
240
+ }
241
+ end
242
+
243
+ return select_fields
244
+ end
245
+
246
+
247
+ ###########################################################################
248
+ # It will generate a new hash with the values generated from the string patterns and select fields specified.
249
+ # In case supplied select_hash_key and a subhash specified on a value it will be selected only the value of the key specified on select_hash_key
250
+ # If expected_errors specified the values will be generated with the specified errors.
251
+ # input:
252
+ # pattern_hash: (Hash) Hash we want to use to generate the values
253
+ # select_hash_key: (key value) (optional) The key we want to select on the subhashes
254
+ # expected_errors: (Array) (optional) (alias: errors) To generate the string patterns with the specified errors.
255
+ # The possible values you can specify is one or more of these ones:
256
+ # :length: wrong length, minimum or maximum
257
+ # :min_length: wrong minimum length
258
+ # :max_length: wrong maximum length
259
+ # :value: wrong resultant value
260
+ # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
261
+ # :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
262
+ # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
263
+ # output: (Hash)
264
+ # The Hash with the select_hash_key selected and the values generated from the string patterns and select fields specified.
265
+ # examples:
266
+ # new_hash = NiceHash.generate(my_hash)
267
+ # #> {:name=>"Peter",
268
+ # :address=>{:wrong=>"\#$$$$$", :correct=>"KZPCzxsWGMLqonesu wbqH"},
269
+ # :city=>{:wrong=>"Germany", :correct=>"Barcelona"},
270
+ # :products=> [
271
+ # {:name=>"gIqkWygmVm", :price=>{:wrong=>"-20", :correct=>"34338330"}},
272
+ # {:name=>"CK68VLIcYf", :price=>{:wrong=>"-20", :correct=>"616066520"}}
273
+ # ]
274
+ # }
275
+ # new_hash = NiceHash.generate(my_hash, :correct)
276
+ # #> {:name=>"Peter",
277
+ # :address=>"juQeAVZjIuWBPsE",
278
+ # :city=>"Madrid",
279
+ # :products=> [
280
+ # {:name=>"G44Ilr0puV", :price=>"477813"},
281
+ # {:name=>"v6ojs79LOp", :price=>"74820"}
282
+ # ]
283
+ # }
284
+ # new_hash = NiceHash.generate(my_hash, :correct, expected_errors: [:min_length])
285
+ # #> {:name=>"Peter",
286
+ # :address=>"ZytjefJ",
287
+ # :city=>"Madri",
288
+ # :products=>[
289
+ # {:name=>"cIBrzeO", :price=>""},
290
+ # {:name=>"5", :price=>""}
291
+ # ]
292
+ # }
293
+ # Using it directly on Hash class, generate(select_hash_key=nil, expected_errors: []) (alias: gen):
294
+ # new_hash = my_hash.generate
295
+ # new_hash = my_hash.gen(:correct)
296
+ # new_hash = my_hash.generate(:correct, errors: [:min_length])
297
+ ###########################################################################
298
+ def NiceHash.generate(pattern_hash, select_hash_key=nil, expected_errors: [], **synonyms)
299
+ hash=Hash.new()
300
+ same_values=Hash.new()
301
+ expected_errors=synonyms[:errors] if synonyms.keys.include?(:errors)
302
+ if expected_errors.kind_of?(Symbol)
303
+ expected_errors=[expected_errors]
304
+ end
305
+
306
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
307
+ pattern_hash.each {|key, value|
308
+
309
+ if key.kind_of?(Array)
310
+ same_values[key[0]]=key.dup
311
+ same_values[key[0]].shift
312
+ key=key[0]
313
+ end
314
+ if value.kind_of?(Hash)
315
+ if value.keys.include?(select_hash_key)
316
+ value=value[select_hash_key]
317
+ else
318
+ value=NiceHash.generate(value, select_hash_key, expected_errors: expected_errors)
319
+ end
320
+ end
321
+
322
+ if value.kind_of?(String) or value.kind_of?(Symbol)
323
+ if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
324
+ hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
325
+ elsif ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
326
+ if expected_errors.include?(:min_length) or (expected_errors.include?(:length) and rand.round==0)
327
+ min=value.to_s.split("|").min {|a, b| a.size <=> b.size}
328
+ hash[key]=min[0..-2] unless min==""
329
+ end
330
+ if !hash.keys.include?(key) and (expected_errors.include?(:max_length) or expected_errors.include?(:length))
331
+ max=value.to_s.split("|").max {|a, b| a.size <=> b.size}
332
+ hash[key]=max+max[-1]
333
+ end
334
+ if expected_errors.include?(:value) or
335
+ expected_errors.include?(:string_set_not_allowed) or
336
+ expected_errors.include?(:required_data)
337
+ if hash.keys.include?(key)
338
+ v=hash[key]
339
+ else
340
+ v=value.to_s.split("|").sample
341
+ end
342
+ unless expected_errors.include?(:string_set_not_allowed)
343
+ v=StringPattern.generate(:"#{v.size}:[#{value.to_s.split("|").join.split(//).uniq.join}]")
344
+ hash[key]=v unless value.to_s.split("|").include?(v)
345
+ end
346
+ unless hash.keys.include?(key)
347
+ one_wrong_letter=StringPattern.generate(:"1:LN$[%#{value.to_s.split("|").join.split(//).uniq.join}%]")
348
+ v[rand(v.size)]=one_wrong_letter
349
+ hash[key]=v unless value.to_s.split("|").include?(v)
350
+ end
351
+ end
352
+ unless hash.keys.include?(key)
353
+ hash[key]=value.to_s.split("|").sample
354
+ end
355
+ else
356
+ hash[key]=value
357
+ end
358
+ elsif value.kind_of?(Array)
359
+ array_pattern=false
360
+ value.each {|v|
361
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
362
+ hash[key]=StringPattern.generate(value, expected_errors: expected_errors)
363
+ array_pattern=true
364
+ break
365
+ end
366
+ }
367
+ unless array_pattern
368
+ value_ret=Array.new
369
+ value.each {|v|
370
+ ret=NiceHash.generate(v, select_hash_key, expected_errors: expected_errors)
371
+ ret=v if ret.kind_of?(Hash) and ret.size==0
372
+ value_ret<<ret
373
+ }
374
+ hash[key]=value_ret
375
+ end
376
+ else
377
+ hash[key]=value
378
+ end
379
+
380
+ if same_values.include?(key)
381
+ same_values[key].each {|k|
382
+ hash[k]=hash[key]
383
+ }
384
+ end
385
+
386
+ }
387
+ end
388
+
389
+ return hash
390
+ end
391
+
392
+
393
+ ###########################################################################
394
+ # Validates a given values_hash_to_validate with string patterns and select fields from pattern_hash
395
+ # input:
396
+ # patterns_hash:
397
+ # (Hash) Hash where we have defined the patterns to follow.
398
+ # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
399
+ # values_hash_to_validate: (Hash) Hash of values to validate
400
+ # only_patterns: (TrueFalse) (by default true) If true it will validate only the patterns and not the other fields
401
+ # output: (Hash)
402
+ # A hash with the validation results. It will return only the validation errors so in case no validation errors found, empty hash.
403
+ # The keys of the hash will be the keys of the values hash with the validation error.
404
+ # The value in case of a pattern, will be an array with one or more of these possibilities:
405
+ # :length: wrong length, minimum or maximum
406
+ # :min_length: wrong minimum length
407
+ # :max_length: wrong maximum length
408
+ # :value: wrong resultant value
409
+ # :required_data: the output string won't include all necessary required data. It works only if required data supplied on the pattern.
410
+ # :excluded_data: the resultant string will include one or more characters that should be excluded. It works only if excluded data supplied on the pattern.
411
+ # :string_set_not_allowed: it will include one or more characters that are not supposed to be on the string.
412
+ # The value in any other case it will be false if the value is not corresponding to the expected.
413
+ # examples:
414
+ # values_to_validate = {:name=>"Peter",
415
+ # :address=>"fnMuKW",
416
+ # :city=>"Dublin",
417
+ # :products=>[{:name=>"V4", :price=>"344"}, {:name=>"E", :price=>"a"}]
418
+ # }
419
+ # results = NiceHash.validate([my_hash, :correct], values_to_validate)
420
+ # #> {:address=>[:min_length, :length],
421
+ # :products=> [{:name=>[:min_length, :length]},
422
+ # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
423
+ # ]
424
+ # }
425
+ # results = NiceHash.validate([my_hash, :correct], values_to_validate, only_patterns: false)
426
+ # #> {:address=>[:min_length, :length],
427
+ # :city=>false,
428
+ # :products=> [{:name=>[:min_length, :length]},
429
+ # {:name=>[:min_length, :length], :price=>[:value, :string_set_not_allowed]}
430
+ # ]
431
+ # }
432
+ # Using it directly on Hash class:
433
+ # validate(select_hash_key=nil, values_hash_to_validate) (alias: val)
434
+ # validate_patterns(select_hash_key=nil, values_hash_to_validate)
435
+ #
436
+ # results = my_hash.validate_patterns(:correct, values_to_validate)
437
+ # results = my_hash.validate(:correct, values_to_validate)
438
+ ###########################################################################
439
+ def NiceHash.validate(patterns_hash, values_hash_to_validate, only_patterns: true)
440
+ if patterns_hash.kind_of?(Array)
441
+ pattern_hash=patterns_hash[0]
442
+ select_hash_key=patterns_hash[1]
443
+ elsif patterns_hash.kind_of?(Hash)
444
+ pattern_hash=patterns_hash
445
+ select_hash_key=nil
446
+ else
447
+ puts "NiceHash.validate wrong pattern_hash supplied #{patterns_hash.inspect}"
448
+ return {error: :error}
449
+ end
450
+ values = values_hash_to_validate
451
+ results={}
452
+ same_values={}
453
+ if pattern_hash.kind_of?(Hash) and pattern_hash.size>0
454
+ pattern_hash.each {|key, value|
455
+
456
+ if key.kind_of?(Array)
457
+ same_values[key[0]]=key.dup
458
+ same_values[key[0]].shift
459
+ key=key[0]
460
+ end
461
+ if value.kind_of?(Hash)
462
+ if !select_hash_key.nil? and value.keys.include?(select_hash_key)
463
+ value=value[select_hash_key]
464
+ elsif values.keys.include?(key) and values[key].kind_of?(Hash)
465
+ res=NiceHash.validate([value, select_hash_key], values[key], only_patterns: only_patterns)
466
+ results[key]=res if res.size>0
467
+ next
468
+ end
469
+ end
470
+
471
+ if values.keys.include?(key)
472
+ if value.kind_of?(String) or value.kind_of?(Symbol)
473
+ if ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^!?\d+-?\d*:.+/).size>0
474
+ res=StringPattern.validate(pattern: value, text: values[key])
475
+ results[key]=res if res.size>0
476
+ elsif !only_patterns and ((StringPattern.optimistic and value.kind_of?(String)) or value.kind_of?(Symbol)) and value.to_s.scan(/^([\w\s\-]+\|)+[\w\s\-]+$/).size>0
477
+ results[key]=false unless value.to_s.split("|").include?(values[key])
478
+ elsif !only_patterns
479
+ results[key]=false unless value.to_s==values[key].to_s
480
+ end
481
+ elsif value.kind_of?(Array)
482
+ array_pattern=false
483
+ complex_data=false
484
+ value.each {|v|
485
+ if (v.kind_of?(String) or v.kind_of?(Symbol)) and StringPattern.analyze(v, silent: true).kind_of?(StringPattern::Pattern)
486
+ res=StringPattern.validate(pattern: value, text: values[key])
487
+ results[key]=res if res==false
488
+ array_pattern=true
489
+ break
490
+ elsif v.kind_of?(Hash) or v.kind_of?(Array) or v.kind_of?(Struct)
491
+ complex_data=true
492
+ break
493
+ end
494
+ }
495
+ unless array_pattern or results.include?(key)
496
+ i=0
497
+ value.each {|v|
498
+ res=NiceHash.validate([v, select_hash_key], values[key][i], only_patterns: only_patterns)
499
+ if res.size>0
500
+ results[key]=Array.new() if !results.keys.include?(key)
501
+ results[key][i]=res
502
+ end
503
+ i+=1
504
+ }
505
+
506
+ end
507
+ unless array_pattern or only_patterns or results.include?(key) or complex_data
508
+ results[key]=false unless value==values[key]
509
+ end
510
+
511
+ else
512
+ unless only_patterns
513
+ results[key]=false unless value==values[key]
514
+ end
515
+ end
516
+
517
+ if same_values.include?(key)
518
+ same_values[key].each {|k|
519
+ if values.keys.include?(k)
520
+ if values[key]!=values[k]
521
+ results[k]="Not equal to #{key}"
522
+ end
523
+ end
524
+ }
525
+ end
526
+
527
+ end
528
+ }
529
+
530
+ end
531
+
532
+ return results
533
+ end
534
+
535
+ ###########################################################################
536
+ # Change only one value at a time and return an Array of Hashes
537
+ # Let's guess we need to test a typical registration REST service and the service has many fields with many validations but we want to test it one field at a time.
538
+ # This method generates values following the patterns on patterns_hash and generates a new hash for every pattern/select field found on patterns_hash using the value supplied on values_hash
539
+ # input:
540
+ # patterns_hash:
541
+ # (Hash) Hash where we have defined the patterns to follow.
542
+ # (Array) In case of array supplied, the pair: [pattern_hash, select_hash_key]. select_hash_key will filter the hash by that key
543
+ # values_hash: (Hash) Hash of values to use to modify the values generated on patterns_hash
544
+ # output: (Array of Hashes)
545
+ # example:
546
+ # wrong_min_length_hash = my_hash.generate(:correct, errors: :min_length)
547
+ # array_of_hashes = NiceHash.change_one_by_one([my_hash, :correct], wrong_min_length_hash)
548
+ # array_of_hashes.each {|hash_with_one_wrong_field|
549
+ # #Here your code to send through http the JSON data stored in hash_with_one_wrong_field
550
+ # #if you want to know which field is the one that is wrong:
551
+ # res = my_hash.validate(:correct, hash_with_one_wrong_field)
552
+ # }
553
+ ###########################################################################
554
+ def NiceHash.change_one_by_one(patterns_hash, values_hash)
555
+ if patterns_hash.kind_of?(Array)
556
+ select_key=patterns_hash[1]
557
+ pattern_hash=patterns_hash[0]
558
+ else
559
+ pattern_hash=patterns_hash
560
+ select_key=[]
561
+ end
562
+ array=Array.new
563
+ good_values=NiceHash.generate(pattern_hash, select_key)
564
+ select_keys=pattern_hash.pattern_fields(select_key)+pattern_hash.select_fields(select_key)
565
+ select_keys.each {|field|
566
+ new_hash=Marshal.load(Marshal.dump(good_values))
567
+ # to deal with the case same values... like in pwd1, pwd2, pwd3
568
+ if field[-1].kind_of?(Array)
569
+ last_to_set=field[-1]
570
+ else
571
+ last_to_set=[field[-1]]
572
+ end
573
+ last_to_set.each {|f|
574
+ keys=field[0..-2]<<f
575
+ new_hash.bury(keys, values_hash.dig(*keys))
576
+ }
577
+ array<<new_hash
578
+ }
579
+ return array
580
+ end
581
+
582
+ end