shark 0.0.0.5.2 → 0.0.0.5.3
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -17
- data/Gemfile +4 -4
- data/README.md +30 -29
- data/Rakefile +1 -1
- data/bin/Shark +544 -544
- data/lib/shark/version.rb +3 -3
- data/lib/shark.rb +5 -5
- data/shark.gemspec +23 -23
- data/src/shark.rb +578 -542
- metadata +9 -15
data/bin/Shark
CHANGED
@@ -1,545 +1,545 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
#Shark is a simple testing tool for testing file system operations. It is still under development
|
4
|
-
|
5
|
-
require 'optparse'
|
6
|
-
require 'fileutils'
|
7
|
-
|
8
|
-
class Shark
|
9
|
-
|
10
|
-
def initialize(a1,a2,a3)
|
11
|
-
|
12
|
-
@features_directory = a1
|
13
|
-
|
14
|
-
@files_directory = a2
|
15
|
-
|
16
|
-
@base_path = a3
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
def start_test
|
21
|
-
|
22
|
-
def read_file_line_by_line(input_path)
|
23
|
-
|
24
|
-
file_id = open(input_path)
|
25
|
-
|
26
|
-
file_line_by_line = file_id.readlines()
|
27
|
-
|
28
|
-
file_id.close
|
29
|
-
|
30
|
-
return file_line_by_line
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def find_file_name(input_path, file_extension)
|
35
|
-
|
36
|
-
extension_remover = input_path.split(file_extension)
|
37
|
-
|
38
|
-
remaining_string = extension_remover[0].reverse
|
39
|
-
|
40
|
-
path_finder = remaining_string.index("/")
|
41
|
-
|
42
|
-
remaining_string = remaining_string.reverse
|
43
|
-
|
44
|
-
return remaining_string[remaining_string.length-path_finder..-1]
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def parse_feature(input_feature_contents)
|
49
|
-
|
50
|
-
#This method extracts scenarios from a feature file
|
51
|
-
|
52
|
-
#Input:
|
53
|
-
#input_feature_contents => An array containing the contents of a feature file
|
54
|
-
|
55
|
-
#Output:
|
56
|
-
#feature_name => Name and description of the feature described in the file
|
57
|
-
#modified_scenarios => An array containing scenario descriptions and scenario steps
|
58
|
-
|
59
|
-
def find_all_matching_indices(input_string,pattern)
|
60
|
-
|
61
|
-
locations = []
|
62
|
-
|
63
|
-
index = input_string.index(pattern)
|
64
|
-
|
65
|
-
while index != nil
|
66
|
-
|
67
|
-
locations << index
|
68
|
-
|
69
|
-
index = input_string.index(pattern,index+1)
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
return locations
|
75
|
-
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
while input_feature_contents[0].eql?("\n")
|
80
|
-
|
81
|
-
input_feature_contents.delete_at(0)
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
feature_contents_string = input_feature_contents.join
|
86
|
-
|
87
|
-
feature_name = ""
|
88
|
-
|
89
|
-
if feature_contents_string.include?("Scenario:")
|
90
|
-
|
91
|
-
feature_name = feature_contents_string[feature_contents_string.index("Feature:")...feature_contents_string.index("Scenario:")].rstrip
|
92
|
-
|
93
|
-
else
|
94
|
-
|
95
|
-
feature_name = feature_contents_string.rstrip
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
scenarios = []
|
100
|
-
|
101
|
-
scenarios_index = find_all_matching_indices(feature_contents_string,"Scenario:")
|
102
|
-
|
103
|
-
scenarios_index << -1
|
104
|
-
|
105
|
-
for x in 0...scenarios_index.length-1
|
106
|
-
|
107
|
-
scenario = feature_contents_string[scenarios_index[x]...scenarios_index[x+1]]
|
108
|
-
|
109
|
-
scenarios << [scenario.lstrip]
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
modified_scenarios = scenarios.dup
|
114
|
-
|
115
|
-
scenario_names = []
|
116
|
-
|
117
|
-
scenarios.each_with_index do |s,index|
|
118
|
-
|
119
|
-
scenario_steps = s[0].split(" ")[1..-1]
|
120
|
-
|
121
|
-
scenario_names << s[0].split(" ")[0]
|
122
|
-
|
123
|
-
modified_scenarios[index] << scenario_steps
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
return feature_name,scenario_names,modified_scenarios
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
def parse_and_test_steps(input_steps,test_files_directory,configuration,config_variables,base_path)
|
132
|
-
|
133
|
-
#This method parses the steps for a given scenario and produces a result using the following keywords
|
134
|
-
|
135
|
-
#Keywords
|
136
|
-
|
137
|
-
#Input
|
138
|
-
#File
|
139
|
-
#When
|
140
|
-
#Run
|
141
|
-
#Output
|
142
|
-
#Equal
|
143
|
-
|
144
|
-
#Input:
|
145
|
-
#input_steps => An array containing the steps
|
146
|
-
|
147
|
-
#Output:
|
148
|
-
#test_result => A string and a boolean containing the results of the test
|
149
|
-
|
150
|
-
def read_file_line_by_line(input_path)
|
151
|
-
|
152
|
-
file_id = open(input_path)
|
153
|
-
|
154
|
-
file_line_by_line = file_id.readlines()
|
155
|
-
|
156
|
-
file_id.close
|
157
|
-
|
158
|
-
return file_line_by_line
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
input_procedures = input_steps.reject {|element| !element.include?("$input")}
|
163
|
-
|
164
|
-
input_file_names = []
|
165
|
-
|
166
|
-
input_procedures.each do |procedure|
|
167
|
-
|
168
|
-
if procedure.include? "$file"
|
169
|
-
|
170
|
-
opening_quotes = procedure.index("\"")
|
171
|
-
|
172
|
-
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
173
|
-
|
174
|
-
input_file_names << file_name
|
175
|
-
|
176
|
-
end
|
177
|
-
|
178
|
-
end
|
179
|
-
|
180
|
-
input_file_contents = input_steps.dup
|
181
|
-
|
182
|
-
test_files_directory = test_files_directory.sub(Dir.pwd,"").sub("/","")
|
183
|
-
|
184
|
-
input_file_names = input_file_names.collect{|element| test_files_directory+element[1..-1]}
|
185
|
-
|
186
|
-
run_procedures = input_file_contents.reject{ |element| !element.include?("$run")}
|
187
|
-
|
188
|
-
run_keywords = ["$cliusage"]
|
189
|
-
|
190
|
-
configuration_vars = config_variables.keys
|
191
|
-
|
192
|
-
modified_keyword_usage = nil
|
193
|
-
|
194
|
-
executable_statements = [[]]*configuration_vars.length
|
195
|
-
|
196
|
-
run_keywords.each do |keyword|
|
197
|
-
|
198
|
-
keyword_usage = configuration.reject { |element| !element.include?(keyword)}
|
199
|
-
|
200
|
-
modified_keyword_usage = keyword_usage.dup
|
201
|
-
|
202
|
-
keyword_usage.each_with_index do |line,index|
|
203
|
-
|
204
|
-
configuration_vars.each_with_index do |var,var_index|
|
205
|
-
|
206
|
-
modified_keyword_usage[index] = modified_keyword_usage[index].gsub(var,"#{config_variables[var]}")
|
207
|
-
|
208
|
-
statement_split = modified_keyword_usage[index].split("=>")
|
209
|
-
|
210
|
-
executable_statements[var_index] << statement_split[1].lstrip.rstrip
|
211
|
-
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
|
216
|
-
end
|
217
|
-
|
218
|
-
configuration_vars.each_with_index do |var,index|
|
219
|
-
|
220
|
-
current_var_run_procedures = run_procedures.reject{|element| !element.include?(var)}
|
221
|
-
|
222
|
-
current_var_run_procedures.each do |run|
|
223
|
-
|
224
|
-
current_executable_statements = executable_statements[index]
|
225
|
-
|
226
|
-
current_executable_statements.each do |executable|
|
227
|
-
|
228
|
-
input_file_names.each do |file_name|
|
229
|
-
|
230
|
-
current_executable_statement = executable.gsub("$file",file_name)
|
231
|
-
|
232
|
-
cli_output = `#{current_executable_statement.strip.lstrip.rstrip}`
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
end
|
237
|
-
|
238
|
-
end
|
239
|
-
|
240
|
-
|
241
|
-
end
|
242
|
-
|
243
|
-
output_procedures = input_steps.reject {|element| !element.include?("$output")}
|
244
|
-
|
245
|
-
matching_file_names = []
|
246
|
-
|
247
|
-
output_file_names = []
|
248
|
-
|
249
|
-
output_procedures.each do |procedure|
|
250
|
-
|
251
|
-
if procedure.include?("$equal") and procedure.include?("$file")
|
252
|
-
|
253
|
-
opening_quotes = procedure.index("\"")
|
254
|
-
|
255
|
-
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
256
|
-
|
257
|
-
matching_file_names << file_name
|
258
|
-
|
259
|
-
else
|
260
|
-
|
261
|
-
opening_quotes = procedure.index("\"")
|
262
|
-
|
263
|
-
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
264
|
-
|
265
|
-
output_file_names << file_name
|
266
|
-
|
267
|
-
end
|
268
|
-
|
269
|
-
end
|
270
|
-
|
271
|
-
output_file_names = output_file_names.collect {|element| test_files_directory + element[1..-1]}
|
272
|
-
|
273
|
-
matching_file_names = matching_file_names.collect {|element| test_files_directory+element[1..-1]}
|
274
|
-
|
275
|
-
output_file_contents = output_file_names.collect{ |element| read_file_line_by_line(element)}
|
276
|
-
|
277
|
-
matching_file_contents = matching_file_names.collect{ |element| read_file_line_by_line(element)}
|
278
|
-
|
279
|
-
test_results = []
|
280
|
-
|
281
|
-
false_results = []
|
282
|
-
|
283
|
-
matching_file_contents.each_with_index do |matching_file,matching_index|
|
284
|
-
|
285
|
-
false_results << [matching_file_names[matching_index]]
|
286
|
-
|
287
|
-
output_file_contents.each_with_index do |output_file,index|
|
288
|
-
|
289
|
-
if matching_file.eql?(output_file)
|
290
|
-
|
291
|
-
test_results << true
|
292
|
-
|
293
|
-
else
|
294
|
-
|
295
|
-
test_results << false
|
296
|
-
|
297
|
-
false_results[-1] << [output_file_names[index]]
|
298
|
-
|
299
|
-
end
|
300
|
-
|
301
|
-
end
|
302
|
-
|
303
|
-
end
|
304
|
-
|
305
|
-
if test_results.include?(false)
|
306
|
-
|
307
|
-
output_string = "\nThe test failed!\n\nA detailed breakdown of the failing files have been given below."
|
308
|
-
|
309
|
-
output_string = output_string + "\n\n"
|
310
|
-
|
311
|
-
detailed_fail_list = ""
|
312
|
-
|
313
|
-
false_results.each do |result|
|
314
|
-
|
315
|
-
detailed_fail_list = detailed_fail_list + "The following files failed in comparison with #{result[0]}"
|
316
|
-
|
317
|
-
failed_files = result[1]
|
318
|
-
|
319
|
-
failed_files.each do |file|
|
320
|
-
|
321
|
-
detailed_fail_list = detailed_fail_list + "\n\n" + "* #{file}\n"
|
322
|
-
|
323
|
-
end
|
324
|
-
|
325
|
-
end
|
326
|
-
|
327
|
-
return output_string = output_string + detailed_fail_list
|
328
|
-
|
329
|
-
else
|
330
|
-
|
331
|
-
return "\nYour test file(s) passed the feature test.\n\n"
|
332
|
-
|
333
|
-
end
|
334
|
-
|
335
|
-
end
|
336
|
-
|
337
|
-
def extract_configurations(feature_contents)
|
338
|
-
|
339
|
-
config_start_index = 0
|
340
|
-
|
341
|
-
feature_contents.each_with_index do |line,index|
|
342
|
-
|
343
|
-
if line.include?("Configurations:")
|
344
|
-
|
345
|
-
config_start_index = index
|
346
|
-
|
347
|
-
end
|
348
|
-
|
349
|
-
end
|
350
|
-
|
351
|
-
modified_feature_contents = feature_contents[0...config_start_index]
|
352
|
-
|
353
|
-
configurations = feature_contents[config_start_index..-1]
|
354
|
-
|
355
|
-
configuration_variables = configurations.join.match(/~\w{1,}/).to_a
|
356
|
-
|
357
|
-
configuration_variable_index = [[]]*configuration_variables.length
|
358
|
-
|
359
|
-
configurations.each_with_index do |line,index|
|
360
|
-
|
361
|
-
configuration_variables.each_with_index do |variable,var_index|
|
362
|
-
|
363
|
-
if line.include?(variable)
|
364
|
-
|
365
|
-
configuration_variable_index[var_index] << index
|
366
|
-
|
367
|
-
end
|
368
|
-
|
369
|
-
end
|
370
|
-
|
371
|
-
end
|
372
|
-
|
373
|
-
def reset_test_files_directory(original_file_list,after_file_list)
|
374
|
-
|
375
|
-
added_files = after_file_list-original_file_list
|
376
|
-
|
377
|
-
added_files.each do |file_name|
|
378
|
-
|
379
|
-
File.delete(file_name)
|
380
|
-
|
381
|
-
end
|
382
|
-
|
383
|
-
end
|
384
|
-
|
385
|
-
configuration_variable_index = configuration_variable_index.collect{ |element| element[0]}
|
386
|
-
|
387
|
-
configuration_variable_index << configurations.length-1
|
388
|
-
|
389
|
-
modified_configurations = configurations.dup
|
390
|
-
|
391
|
-
for x in 0...configuration_variable_index.length-1
|
392
|
-
|
393
|
-
current_index = configuration_variable_index[x]
|
394
|
-
|
395
|
-
current_variable = configuration_variables[x]
|
396
|
-
|
397
|
-
for y in current_index..configuration_variable_index[x+1]
|
398
|
-
|
399
|
-
modified_configurations[y] = configurations[y].gsub(":v",current_variable)
|
400
|
-
|
401
|
-
end
|
402
|
-
|
403
|
-
end
|
404
|
-
|
405
|
-
configuration_var_values = []
|
406
|
-
|
407
|
-
configuration_variable_index.delete_at(1)
|
408
|
-
|
409
|
-
configuration_variable_index.each do |index|
|
410
|
-
|
411
|
-
var_split = modified_configurations[index].split("=>")
|
412
|
-
|
413
|
-
var_value = var_split[1].lstrip.rstrip
|
414
|
-
|
415
|
-
configuration_var_values << var_value
|
416
|
-
|
417
|
-
end
|
418
|
-
|
419
|
-
configuration_values = Hash[configuration_variables.zip(configuration_var_values)]
|
420
|
-
|
421
|
-
return modified_feature_contents,modified_configurations,configuration_values
|
422
|
-
|
423
|
-
end
|
424
|
-
|
425
|
-
list_of_features = []
|
426
|
-
|
427
|
-
Dir.foreach(@features_directory) { |x| list_of_features << @features_directory+"#{x}" }
|
428
|
-
|
429
|
-
initial_files_list = []
|
430
|
-
|
431
|
-
Dir.foreach(@files_directory) { |x| initial_files_list << @files_directory+"#{x}" }
|
432
|
-
|
433
|
-
list_of_features = list_of_features.reject { |path| !path.include?(".feature")}
|
434
|
-
|
435
|
-
list_of_features.each do |feature_path|
|
436
|
-
|
437
|
-
feature_contents = read_file_line_by_line(feature_path)
|
438
|
-
|
439
|
-
feature_contents,configurations,config_values = extract_configurations(feature_contents)
|
440
|
-
|
441
|
-
feature_name,scenario_names,scenarios = parse_feature(feature_contents)
|
442
|
-
|
443
|
-
puts feature_name
|
444
|
-
|
445
|
-
scenarios.each_with_index do |scenario,index|
|
446
|
-
|
447
|
-
puts "\n#{scenario_names[index]}"
|
448
|
-
|
449
|
-
scenario[1] = scenario[1].collect{|element| element.sub("input","$input")}
|
450
|
-
|
451
|
-
scenario[1] = scenario[1].collect{|element| element.sub("file","$file")}
|
452
|
-
|
453
|
-
scenario[1] = scenario[1].collect{|element| element.sub("run","$run")}
|
454
|
-
|
455
|
-
scenario[1] = scenario[1].collect{|element| element.sub("output","$output")}
|
456
|
-
|
457
|
-
scenario[1] = scenario[1].collect{|element| element.sub("equal","$equal")}
|
458
|
-
|
459
|
-
output = parse_and_test_steps(scenario[1],@files_directory,configurations,config_values,@base_path)
|
460
|
-
|
461
|
-
puts output
|
462
|
-
|
463
|
-
end
|
464
|
-
|
465
|
-
puts "\n"
|
466
|
-
|
467
|
-
end
|
468
|
-
|
469
|
-
after_files_list = []
|
470
|
-
|
471
|
-
Dir.foreach(@files_directory) { |x| after_files_list << @files_directory+"#{x}" }
|
472
|
-
|
473
|
-
reset_test_files_directory(initial_files_list,after_files_list)
|
474
|
-
|
475
|
-
end
|
476
|
-
|
477
|
-
end
|
478
|
-
|
479
|
-
def create_mac_executable(input_file)
|
480
|
-
|
481
|
-
def read_file_line_by_line(input_path)
|
482
|
-
|
483
|
-
file_id = open(input_path)
|
484
|
-
|
485
|
-
file_line_by_line = file_id.readlines()
|
486
|
-
|
487
|
-
file_id.close
|
488
|
-
|
489
|
-
return file_line_by_line
|
490
|
-
|
491
|
-
end
|
492
|
-
|
493
|
-
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
494
|
-
|
495
|
-
mac_file_path = input_file.sub(".rb","")
|
496
|
-
|
497
|
-
file_id = open(mac_file_path,"w")
|
498
|
-
|
499
|
-
file_id.write(mac_file_contents.join)
|
500
|
-
|
501
|
-
file_id.close
|
502
|
-
|
503
|
-
end
|
504
|
-
|
505
|
-
OptionParser.new do |opts|
|
506
|
-
|
507
|
-
opts.banner = "Usage: shark [options]"
|
508
|
-
|
509
|
-
opts.on("-t", "--test", "Start Test") do
|
510
|
-
|
511
|
-
current_directory = Dir.pwd + "/shark/"
|
512
|
-
|
513
|
-
base_path = Dir.pwd
|
514
|
-
|
515
|
-
features_directory = current_directory + "features/"
|
516
|
-
|
517
|
-
test_files_directory = current_directory + "test_files/"
|
518
|
-
|
519
|
-
tester = Shark.new(features_directory, test_files_directory, base_path)
|
520
|
-
|
521
|
-
tester.start_test()
|
522
|
-
|
523
|
-
end
|
524
|
-
|
525
|
-
opts.on("-i","--init","Initialize Shark in this project") do
|
526
|
-
|
527
|
-
FileUtils.mkdir_p "Shark\\features"
|
528
|
-
|
529
|
-
FileUtils.mkdir_p "Shark\\test_files"
|
530
|
-
|
531
|
-
puts "Shark has been successfully initialized!"
|
532
|
-
|
533
|
-
end
|
534
|
-
|
535
|
-
opts.on("-m", "--buildmac", "Builds Mac Executables") do
|
536
|
-
|
537
|
-
file_path = Dir.pwd + "/shark.rb"
|
538
|
-
|
539
|
-
create_mac_executable(file_path)
|
540
|
-
|
541
|
-
puts "Build Successful!"
|
542
|
-
|
543
|
-
end
|
544
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#Shark is a simple testing tool for testing file system operations. It is still under development
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
class Shark
|
9
|
+
|
10
|
+
def initialize(a1,a2,a3)
|
11
|
+
|
12
|
+
@features_directory = a1
|
13
|
+
|
14
|
+
@files_directory = a2
|
15
|
+
|
16
|
+
@base_path = a3
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def start_test
|
21
|
+
|
22
|
+
def read_file_line_by_line(input_path)
|
23
|
+
|
24
|
+
file_id = open(input_path)
|
25
|
+
|
26
|
+
file_line_by_line = file_id.readlines()
|
27
|
+
|
28
|
+
file_id.close
|
29
|
+
|
30
|
+
return file_line_by_line
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_file_name(input_path, file_extension)
|
35
|
+
|
36
|
+
extension_remover = input_path.split(file_extension)
|
37
|
+
|
38
|
+
remaining_string = extension_remover[0].reverse
|
39
|
+
|
40
|
+
path_finder = remaining_string.index("/")
|
41
|
+
|
42
|
+
remaining_string = remaining_string.reverse
|
43
|
+
|
44
|
+
return remaining_string[remaining_string.length-path_finder..-1]
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_feature(input_feature_contents)
|
49
|
+
|
50
|
+
#This method extracts scenarios from a feature file
|
51
|
+
|
52
|
+
#Input:
|
53
|
+
#input_feature_contents => An array containing the contents of a feature file
|
54
|
+
|
55
|
+
#Output:
|
56
|
+
#feature_name => Name and description of the feature described in the file
|
57
|
+
#modified_scenarios => An array containing scenario descriptions and scenario steps
|
58
|
+
|
59
|
+
def find_all_matching_indices(input_string,pattern)
|
60
|
+
|
61
|
+
locations = []
|
62
|
+
|
63
|
+
index = input_string.index(pattern)
|
64
|
+
|
65
|
+
while index != nil
|
66
|
+
|
67
|
+
locations << index
|
68
|
+
|
69
|
+
index = input_string.index(pattern,index+1)
|
70
|
+
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
return locations
|
75
|
+
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
while input_feature_contents[0].eql?("\n")
|
80
|
+
|
81
|
+
input_feature_contents.delete_at(0)
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
feature_contents_string = input_feature_contents.join
|
86
|
+
|
87
|
+
feature_name = ""
|
88
|
+
|
89
|
+
if feature_contents_string.include?("Scenario:")
|
90
|
+
|
91
|
+
feature_name = feature_contents_string[feature_contents_string.index("Feature:")...feature_contents_string.index("Scenario:")].rstrip
|
92
|
+
|
93
|
+
else
|
94
|
+
|
95
|
+
feature_name = feature_contents_string.rstrip
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
scenarios = []
|
100
|
+
|
101
|
+
scenarios_index = find_all_matching_indices(feature_contents_string,"Scenario:")
|
102
|
+
|
103
|
+
scenarios_index << -1
|
104
|
+
|
105
|
+
for x in 0...scenarios_index.length-1
|
106
|
+
|
107
|
+
scenario = feature_contents_string[scenarios_index[x]...scenarios_index[x+1]]
|
108
|
+
|
109
|
+
scenarios << [scenario.lstrip]
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
modified_scenarios = scenarios.dup
|
114
|
+
|
115
|
+
scenario_names = []
|
116
|
+
|
117
|
+
scenarios.each_with_index do |s,index|
|
118
|
+
|
119
|
+
scenario_steps = s[0].split(" ")[1..-1]
|
120
|
+
|
121
|
+
scenario_names << s[0].split(" ")[0]
|
122
|
+
|
123
|
+
modified_scenarios[index] << scenario_steps
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
return feature_name,scenario_names,modified_scenarios
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
def parse_and_test_steps(input_steps,test_files_directory,configuration,config_variables,base_path)
|
132
|
+
|
133
|
+
#This method parses the steps for a given scenario and produces a result using the following keywords
|
134
|
+
|
135
|
+
#Keywords
|
136
|
+
|
137
|
+
#Input
|
138
|
+
#File
|
139
|
+
#When
|
140
|
+
#Run
|
141
|
+
#Output
|
142
|
+
#Equal
|
143
|
+
|
144
|
+
#Input:
|
145
|
+
#input_steps => An array containing the steps
|
146
|
+
|
147
|
+
#Output:
|
148
|
+
#test_result => A string and a boolean containing the results of the test
|
149
|
+
|
150
|
+
def read_file_line_by_line(input_path)
|
151
|
+
|
152
|
+
file_id = open(input_path)
|
153
|
+
|
154
|
+
file_line_by_line = file_id.readlines()
|
155
|
+
|
156
|
+
file_id.close
|
157
|
+
|
158
|
+
return file_line_by_line
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
input_procedures = input_steps.reject {|element| !element.include?("$input")}
|
163
|
+
|
164
|
+
input_file_names = []
|
165
|
+
|
166
|
+
input_procedures.each do |procedure|
|
167
|
+
|
168
|
+
if procedure.include? "$file"
|
169
|
+
|
170
|
+
opening_quotes = procedure.index("\"")
|
171
|
+
|
172
|
+
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
173
|
+
|
174
|
+
input_file_names << file_name
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
input_file_contents = input_steps.dup
|
181
|
+
|
182
|
+
test_files_directory = test_files_directory.sub(Dir.pwd,"").sub("/","")
|
183
|
+
|
184
|
+
input_file_names = input_file_names.collect{|element| test_files_directory+element[1..-1]}
|
185
|
+
|
186
|
+
run_procedures = input_file_contents.reject{ |element| !element.include?("$run")}
|
187
|
+
|
188
|
+
run_keywords = ["$cliusage"]
|
189
|
+
|
190
|
+
configuration_vars = config_variables.keys
|
191
|
+
|
192
|
+
modified_keyword_usage = nil
|
193
|
+
|
194
|
+
executable_statements = [[]]*configuration_vars.length
|
195
|
+
|
196
|
+
run_keywords.each do |keyword|
|
197
|
+
|
198
|
+
keyword_usage = configuration.reject { |element| !element.include?(keyword)}
|
199
|
+
|
200
|
+
modified_keyword_usage = keyword_usage.dup
|
201
|
+
|
202
|
+
keyword_usage.each_with_index do |line,index|
|
203
|
+
|
204
|
+
configuration_vars.each_with_index do |var,var_index|
|
205
|
+
|
206
|
+
modified_keyword_usage[index] = modified_keyword_usage[index].gsub(var,"#{config_variables[var]}")
|
207
|
+
|
208
|
+
statement_split = modified_keyword_usage[index].split("=>")
|
209
|
+
|
210
|
+
executable_statements[var_index] << statement_split[1].lstrip.rstrip
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
configuration_vars.each_with_index do |var,index|
|
219
|
+
|
220
|
+
current_var_run_procedures = run_procedures.reject{|element| !element.include?(var)}
|
221
|
+
|
222
|
+
current_var_run_procedures.each do |run|
|
223
|
+
|
224
|
+
current_executable_statements = executable_statements[index]
|
225
|
+
|
226
|
+
current_executable_statements.each do |executable|
|
227
|
+
|
228
|
+
input_file_names.each do |file_name|
|
229
|
+
|
230
|
+
current_executable_statement = executable.gsub("$file",file_name)
|
231
|
+
|
232
|
+
cli_output = `#{current_executable_statement.strip.lstrip.rstrip}`
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
output_procedures = input_steps.reject {|element| !element.include?("$output")}
|
244
|
+
|
245
|
+
matching_file_names = []
|
246
|
+
|
247
|
+
output_file_names = []
|
248
|
+
|
249
|
+
output_procedures.each do |procedure|
|
250
|
+
|
251
|
+
if procedure.include?("$equal") and procedure.include?("$file")
|
252
|
+
|
253
|
+
opening_quotes = procedure.index("\"")
|
254
|
+
|
255
|
+
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
256
|
+
|
257
|
+
matching_file_names << file_name
|
258
|
+
|
259
|
+
else
|
260
|
+
|
261
|
+
opening_quotes = procedure.index("\"")
|
262
|
+
|
263
|
+
file_name = procedure[opening_quotes...procedure.index("\"",opening_quotes+1)]
|
264
|
+
|
265
|
+
output_file_names << file_name
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
output_file_names = output_file_names.collect {|element| test_files_directory + element[1..-1]}
|
272
|
+
|
273
|
+
matching_file_names = matching_file_names.collect {|element| test_files_directory+element[1..-1]}
|
274
|
+
|
275
|
+
output_file_contents = output_file_names.collect{ |element| read_file_line_by_line(element)}
|
276
|
+
|
277
|
+
matching_file_contents = matching_file_names.collect{ |element| read_file_line_by_line(element)}
|
278
|
+
|
279
|
+
test_results = []
|
280
|
+
|
281
|
+
false_results = []
|
282
|
+
|
283
|
+
matching_file_contents.each_with_index do |matching_file,matching_index|
|
284
|
+
|
285
|
+
false_results << [matching_file_names[matching_index]]
|
286
|
+
|
287
|
+
output_file_contents.each_with_index do |output_file,index|
|
288
|
+
|
289
|
+
if matching_file.eql?(output_file)
|
290
|
+
|
291
|
+
test_results << true
|
292
|
+
|
293
|
+
else
|
294
|
+
|
295
|
+
test_results << false
|
296
|
+
|
297
|
+
false_results[-1] << [output_file_names[index]]
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
if test_results.include?(false)
|
306
|
+
|
307
|
+
output_string = "\nThe test failed!\n\nA detailed breakdown of the failing files have been given below."
|
308
|
+
|
309
|
+
output_string = output_string + "\n\n"
|
310
|
+
|
311
|
+
detailed_fail_list = ""
|
312
|
+
|
313
|
+
false_results.each do |result|
|
314
|
+
|
315
|
+
detailed_fail_list = detailed_fail_list + "The following files failed in comparison with #{result[0]}"
|
316
|
+
|
317
|
+
failed_files = result[1]
|
318
|
+
|
319
|
+
failed_files.each do |file|
|
320
|
+
|
321
|
+
detailed_fail_list = detailed_fail_list + "\n\n" + "* #{file}\n"
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
return output_string = output_string + detailed_fail_list
|
328
|
+
|
329
|
+
else
|
330
|
+
|
331
|
+
return "\nYour test file(s) passed the feature test.\n\n"
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
def extract_configurations(feature_contents)
|
338
|
+
|
339
|
+
config_start_index = 0
|
340
|
+
|
341
|
+
feature_contents.each_with_index do |line,index|
|
342
|
+
|
343
|
+
if line.include?("Configurations:")
|
344
|
+
|
345
|
+
config_start_index = index
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
modified_feature_contents = feature_contents[0...config_start_index]
|
352
|
+
|
353
|
+
configurations = feature_contents[config_start_index..-1]
|
354
|
+
|
355
|
+
configuration_variables = configurations.join.match(/~\w{1,}/).to_a
|
356
|
+
|
357
|
+
configuration_variable_index = [[]]*configuration_variables.length
|
358
|
+
|
359
|
+
configurations.each_with_index do |line,index|
|
360
|
+
|
361
|
+
configuration_variables.each_with_index do |variable,var_index|
|
362
|
+
|
363
|
+
if line.include?(variable)
|
364
|
+
|
365
|
+
configuration_variable_index[var_index] << index
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
def reset_test_files_directory(original_file_list,after_file_list)
|
374
|
+
|
375
|
+
added_files = after_file_list-original_file_list
|
376
|
+
|
377
|
+
added_files.each do |file_name|
|
378
|
+
|
379
|
+
File.delete(file_name)
|
380
|
+
|
381
|
+
end
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
configuration_variable_index = configuration_variable_index.collect{ |element| element[0]}
|
386
|
+
|
387
|
+
configuration_variable_index << configurations.length-1
|
388
|
+
|
389
|
+
modified_configurations = configurations.dup
|
390
|
+
|
391
|
+
for x in 0...configuration_variable_index.length-1
|
392
|
+
|
393
|
+
current_index = configuration_variable_index[x]
|
394
|
+
|
395
|
+
current_variable = configuration_variables[x]
|
396
|
+
|
397
|
+
for y in current_index..configuration_variable_index[x+1]
|
398
|
+
|
399
|
+
modified_configurations[y] = configurations[y].gsub(":v",current_variable)
|
400
|
+
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
configuration_var_values = []
|
406
|
+
|
407
|
+
configuration_variable_index.delete_at(1)
|
408
|
+
|
409
|
+
configuration_variable_index.each do |index|
|
410
|
+
|
411
|
+
var_split = modified_configurations[index].split("=>")
|
412
|
+
|
413
|
+
var_value = var_split[1].lstrip.rstrip
|
414
|
+
|
415
|
+
configuration_var_values << var_value
|
416
|
+
|
417
|
+
end
|
418
|
+
|
419
|
+
configuration_values = Hash[configuration_variables.zip(configuration_var_values)]
|
420
|
+
|
421
|
+
return modified_feature_contents,modified_configurations,configuration_values
|
422
|
+
|
423
|
+
end
|
424
|
+
|
425
|
+
list_of_features = []
|
426
|
+
|
427
|
+
Dir.foreach(@features_directory) { |x| list_of_features << @features_directory+"#{x}" }
|
428
|
+
|
429
|
+
initial_files_list = []
|
430
|
+
|
431
|
+
Dir.foreach(@files_directory) { |x| initial_files_list << @files_directory+"#{x}" }
|
432
|
+
|
433
|
+
list_of_features = list_of_features.reject { |path| !path.include?(".feature")}
|
434
|
+
|
435
|
+
list_of_features.each do |feature_path|
|
436
|
+
|
437
|
+
feature_contents = read_file_line_by_line(feature_path)
|
438
|
+
|
439
|
+
feature_contents,configurations,config_values = extract_configurations(feature_contents)
|
440
|
+
|
441
|
+
feature_name,scenario_names,scenarios = parse_feature(feature_contents)
|
442
|
+
|
443
|
+
puts feature_name
|
444
|
+
|
445
|
+
scenarios.each_with_index do |scenario,index|
|
446
|
+
|
447
|
+
puts "\n#{scenario_names[index]}"
|
448
|
+
|
449
|
+
scenario[1] = scenario[1].collect{|element| element.sub("input","$input")}
|
450
|
+
|
451
|
+
scenario[1] = scenario[1].collect{|element| element.sub("file","$file")}
|
452
|
+
|
453
|
+
scenario[1] = scenario[1].collect{|element| element.sub("run","$run")}
|
454
|
+
|
455
|
+
scenario[1] = scenario[1].collect{|element| element.sub("output","$output")}
|
456
|
+
|
457
|
+
scenario[1] = scenario[1].collect{|element| element.sub("equal","$equal")}
|
458
|
+
|
459
|
+
output = parse_and_test_steps(scenario[1],@files_directory,configurations,config_values,@base_path)
|
460
|
+
|
461
|
+
puts output
|
462
|
+
|
463
|
+
end
|
464
|
+
|
465
|
+
puts "\n"
|
466
|
+
|
467
|
+
end
|
468
|
+
|
469
|
+
after_files_list = []
|
470
|
+
|
471
|
+
Dir.foreach(@files_directory) { |x| after_files_list << @files_directory+"#{x}" }
|
472
|
+
|
473
|
+
reset_test_files_directory(initial_files_list,after_files_list)
|
474
|
+
|
475
|
+
end
|
476
|
+
|
477
|
+
end
|
478
|
+
|
479
|
+
def create_mac_executable(input_file)
|
480
|
+
|
481
|
+
def read_file_line_by_line(input_path)
|
482
|
+
|
483
|
+
file_id = open(input_path)
|
484
|
+
|
485
|
+
file_line_by_line = file_id.readlines()
|
486
|
+
|
487
|
+
file_id.close
|
488
|
+
|
489
|
+
return file_line_by_line
|
490
|
+
|
491
|
+
end
|
492
|
+
|
493
|
+
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
494
|
+
|
495
|
+
mac_file_path = input_file.sub(".rb","")
|
496
|
+
|
497
|
+
file_id = open(mac_file_path,"w")
|
498
|
+
|
499
|
+
file_id.write(mac_file_contents.join)
|
500
|
+
|
501
|
+
file_id.close
|
502
|
+
|
503
|
+
end
|
504
|
+
|
505
|
+
OptionParser.new do |opts|
|
506
|
+
|
507
|
+
opts.banner = "Usage: shark [options]"
|
508
|
+
|
509
|
+
opts.on("-t", "--test", "Start Test") do
|
510
|
+
|
511
|
+
current_directory = Dir.pwd + "/shark/"
|
512
|
+
|
513
|
+
base_path = Dir.pwd
|
514
|
+
|
515
|
+
features_directory = current_directory + "features/"
|
516
|
+
|
517
|
+
test_files_directory = current_directory + "test_files/"
|
518
|
+
|
519
|
+
tester = Shark.new(features_directory, test_files_directory, base_path)
|
520
|
+
|
521
|
+
tester.start_test()
|
522
|
+
|
523
|
+
end
|
524
|
+
|
525
|
+
opts.on("-i","--init","Initialize Shark in this project") do
|
526
|
+
|
527
|
+
FileUtils.mkdir_p "Shark\\features"
|
528
|
+
|
529
|
+
FileUtils.mkdir_p "Shark\\test_files"
|
530
|
+
|
531
|
+
puts "Shark has been successfully initialized!"
|
532
|
+
|
533
|
+
end
|
534
|
+
|
535
|
+
opts.on("-m", "--buildmac", "Builds Mac Executables") do
|
536
|
+
|
537
|
+
file_path = Dir.pwd + "/shark.rb"
|
538
|
+
|
539
|
+
create_mac_executable(file_path)
|
540
|
+
|
541
|
+
puts "Build Successful!"
|
542
|
+
|
543
|
+
end
|
544
|
+
|
545
545
|
end.parse!
|