kronk 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,49 @@
1
+ class Kronk
2
+
3
+ class Diff
4
+
5
+ ##
6
+ # Format diff with ascii
7
+
8
+ class ColorFormat
9
+
10
+ def self.ensure_color
11
+ return unless Kronk::Cmd.windows?
12
+ begin
13
+ require 'Win32/Console/ANSI'
14
+ rescue LoadError
15
+ Cmd.warn "You must gem install win32console to use color"
16
+ end
17
+ end
18
+
19
+
20
+ def self.lines line_nums, col_width
21
+ ensure_color
22
+
23
+ out =
24
+ [*line_nums].map do |lnum|
25
+ lnum.to_s.rjust col_width
26
+ end.join "\033[32m"
27
+
28
+ "\033[7;31m#{out}\033[0m "
29
+ end
30
+
31
+
32
+ def self.deleted str
33
+ ensure_color
34
+ "\033[31m- #{str}\033[0m"
35
+ end
36
+
37
+
38
+ def self.added str
39
+ ensure_color
40
+ "\033[32m+ #{str}\033[0m"
41
+ end
42
+
43
+
44
+ def self.common str
45
+ " #{str}"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -19,7 +19,7 @@ class Kronk
19
19
  # number of redirects left if it's an Integer.
20
20
 
21
21
  def self.follow_redirect resp, options={}
22
- Kronk.verbose "Following redirect..."
22
+ Kronk::Cmd.verbose "Following redirect..."
23
23
 
24
24
  rdir = options[:follow_redirects]
25
25
  rdir = rdir - 1 if Integer === rdir && rdir > 0
@@ -84,7 +84,7 @@ class Kronk
84
84
  # Read http response from a file and return a HTTPResponse instance.
85
85
 
86
86
  def self.retrieve_file path, options={}
87
- Kronk.verbose "Reading file: #{path}\n"
87
+ Kronk::Cmd.verbose "Reading file: #{path}\n"
88
88
 
89
89
  options = options.dup
90
90
 
@@ -95,7 +95,7 @@ class Kronk
95
95
 
96
96
  # On windows, read the full file and insert contents into
97
97
  # a StringIO to avoid failures with IO#read_nonblock
98
- file = StringIO.new file.read if Kronk.windows?
98
+ file = StringIO.new file.read if Kronk::Cmd.windows?
99
99
 
100
100
  begin
101
101
  resp = Response.read_new file
@@ -117,7 +117,7 @@ class Kronk
117
117
  # Read the http response from an IO instance and return a HTTPResponse.
118
118
 
119
119
  def self.retrieve_io io, options={}
120
- Kronk.verbose "Reading IO..."
120
+ Kronk::Cmd.verbose "Reading IO..."
121
121
 
122
122
  options = options.dup
123
123
 
@@ -221,7 +221,7 @@ class Kronk
221
221
  options[:auth][:password]
222
222
  end
223
223
 
224
- Kronk.verbose "Retrieving URL: #{uri}\n"
224
+ Kronk::Cmd.verbose "Retrieving URL: #{uri}\n"
225
225
 
226
226
  http.request req, data
227
227
  end
@@ -289,7 +289,7 @@ class Kronk
289
289
  user = proxy_opts[:username]
290
290
  pass = proxy_opts[:password]
291
291
 
292
- Kronk.verbose "Using proxy #{addr}\n" if host
292
+ Kronk::Cmd.verbose "Using proxy #{addr}\n" if host
293
293
 
294
294
  Net::HTTP::Proxy host, port, user, pass
295
295
  end
@@ -0,0 +1,15 @@
1
+ class Kronk
2
+
3
+ ##
4
+ # Test module that includes kronk assertions, request helper methods,
5
+ # and core extensions.
6
+
7
+ module Test
8
+ require 'kronk/test/assertions'
9
+ require 'kronk/test/core_ext'
10
+ require 'kronk/test/helper_methods'
11
+
12
+ include Assertions
13
+ include HelperMethods
14
+ end
15
+ end
@@ -0,0 +1,97 @@
1
+ class Kronk
2
+
3
+ module Test
4
+
5
+ module Assertions
6
+
7
+ ##
8
+ # Assert that the given path exists in data.
9
+ # Supports all DataSet#find_data path types.
10
+
11
+ def assert_data_at data, path, msg=nil
12
+ msg ||= "No data found at #{path.inspect} for #{data.inspect}"
13
+ found = false
14
+
15
+ data_set = Kronk::DataSet.new data
16
+ data_set.find_data path do |d,k,p|
17
+ found = true
18
+ break
19
+ end
20
+
21
+ assert found, msg
22
+ end
23
+
24
+
25
+ ##
26
+ # Assert that the given path doesn't exist in data.
27
+ # Supports all DataSet#find_data path types.
28
+
29
+ def assert_no_data_at data, path, msg=nil
30
+ msg ||= "Data found at #{path.inspect} for #{data.inspect}"
31
+ found = false
32
+
33
+ data_set = Kronk::DataSet.new data
34
+ data_set.find_data path do |d,k,p|
35
+ found = true
36
+ break
37
+ end
38
+
39
+ assert !found, msg
40
+ end
41
+
42
+
43
+ ##
44
+ # Assert that at least one data point found with the given path is equal
45
+ # to the given match.
46
+ # Supports all DataSet#find_data path types.
47
+
48
+ def assert_data_at_equal data, path, match, msg=nil
49
+ last_data = nil
50
+ found = false
51
+
52
+ data_set = Kronk::DataSet.new data
53
+ data_set.find_data path do |d,k,p|
54
+ found = true
55
+ last_data = d[k]
56
+ break if d[k] == match
57
+ end
58
+
59
+ assert found,
60
+ msg || "No data found at #{path.inspect} for #{data.inspect}"
61
+
62
+ assert_equal match, last_data, msg
63
+ end
64
+
65
+
66
+ ##
67
+ # Assert that no data points found with the given path are equal
68
+ # to the given match.
69
+ # Supports all DataSet#find_data path types.
70
+
71
+ def assert_data_at_not_equal data, path, match, msg=nil
72
+ last_data = nil
73
+
74
+ data_set = Kronk::DataSet.new data
75
+ data_set.find_data path do |d,k,p|
76
+ last_data = d[k]
77
+ break if d[k] == match
78
+ end
79
+
80
+ assert_not_equal match, last_data, msg
81
+ end
82
+
83
+
84
+ ##
85
+ # Makes request to both uris and asserts that the parsed data they
86
+ # return is equal. Compares response body if data is unparsable.
87
+ # Supports all options of Kronk.compare.
88
+
89
+ def assert_equal_responses uri1, uri2, options={}
90
+ resp1 = Kronk.retrieve_data_string uri1, options
91
+ resp2 = Kronk.retrieve_data_string uri2, options
92
+
93
+ assert_equal resp1, resp2
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,65 @@
1
+ class Kronk
2
+
3
+ module Test
4
+
5
+ ##
6
+ # Data manipulation and retrieval methods for Array and Hash classes.
7
+
8
+ module DataExt
9
+
10
+ ##
11
+ # Checks if the given path exists and returns the first matching path
12
+ # as an array of keys. Returns nil if no path is found.
13
+
14
+ def has_path? path
15
+ Kronk::DataSet.new(self).find_data path do |d,k,p|
16
+ return !!p
17
+ end
18
+
19
+ nil
20
+ end
21
+
22
+
23
+ ##
24
+ # Looks for data at paths matching path. Returns a hash of
25
+ # path array => data value pairs.
26
+ #
27
+ # If given a block will pass the parent data structure, the key
28
+ # or index of the item at given path, and the full path
29
+ # as an array of keys for each found path.
30
+ #
31
+ # data = {:foo => "bar", :foobar => [:a, :b, {:foo => "other bar"}, :c]}
32
+ # data.find_data "**/foo" do |parent, key, path|
33
+ # p path
34
+ # p parent[key]
35
+ # puts "---"
36
+ # end
37
+ #
38
+ # # outputs:
39
+ # # [:foo]
40
+ # # "bar"
41
+ # # ---
42
+ # # [:foobar, 2, :foo]
43
+ # # "other bar"
44
+ # # ---
45
+ #
46
+ # # returns:
47
+ # # {[:foo] => "bar", [:foobar, 2, :foo] => "other bar"}
48
+
49
+ def find_data path
50
+ found = {}
51
+
52
+ Kronk::DataSet.new(self).find_data path do |d,k,p|
53
+ found[p] = d[k]
54
+ yield d, k, p if block_given?
55
+ end
56
+
57
+ found
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+
64
+ Array.send :include, Kronk::Test::DataExt
65
+ Hash.send :include, Kronk::Test::DataExt
@@ -0,0 +1,86 @@
1
+ class Kronk
2
+
3
+ module Test
4
+
5
+ ##
6
+ # Kronk test helper methods to easily make and mock requests.
7
+ # Sets @responses, @response, @datas, @data, and @diff instance variables.
8
+
9
+ module HelperMethods
10
+
11
+ ##
12
+ # Do a get request for one or two URIs.
13
+ # See Kronk#compare for all supported options.
14
+
15
+ def get uri1, uri2=nil, options={}
16
+ retrieve uri1, uri2, options.merge(:http_method => :get)
17
+ end
18
+
19
+
20
+ ##
21
+ # Do a post request for one or two URIs.
22
+ # See Kronk#compare for all supported options.
23
+
24
+ def post uri1, uri2=nil, options={}
25
+ retrieve uri1, uri2, options.merge(:http_method => :post)
26
+ end
27
+
28
+
29
+ ##
30
+ # Do a put request for one or two URIs.
31
+ # See Kronk#compare for all supported options.
32
+
33
+ def put uri1, uri2=nil, options={}
34
+ retrieve uri1, uri2, options.merge(:http_method => :put)
35
+ end
36
+
37
+
38
+ ##
39
+ # Do a delete request for one or two URIs.
40
+ # See Kronk#compare for all supported options.
41
+
42
+ def delete uri1, uri2=nil, options={}
43
+ retrieve uri1, uri2, options.merge(:http_method => :delete)
44
+ end
45
+
46
+
47
+ protected
48
+
49
+ def retrieve uri1, uri2=nil, options={}
50
+ uri2, options = nil, uri2.merge(options) if Hash === uri2
51
+
52
+ if uri2
53
+ @responses = [Request.retrieve(uri1, options),
54
+ Request.retrieve(uri2, options)]
55
+ @response = @responses.last
56
+
57
+ @datas = @responses.map do |r|
58
+ begin
59
+ r.selective_data options
60
+ rescue Kronk::Response::MissingParser
61
+ r.body
62
+ end
63
+ end
64
+
65
+ @data = @datas.last
66
+
67
+ @diff = Diff.new_from_data(*@datas)
68
+
69
+ else
70
+ @response = Request.retrieve uri1, options
71
+ @responses = [@response]
72
+
73
+ @data = begin
74
+ @response.selective_data options
75
+ rescue Kronk::Response::MissingParser
76
+ @response.body
77
+ end
78
+
79
+ @datas = [@data]
80
+
81
+ @diff = nil
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,174 @@
1
+ require 'rubygems'
2
+ require 'kronk'
3
+
4
+ ##
5
+ # Yzma bosses Kronk around to give you meaningful diff variation
6
+ # statistical data:
7
+ # Yzma.report "My Report" do
8
+ # compare uri1, uri2, :count => 100 do
9
+ # randomize_param :limit, 20..200, :optional => true, :allow_blank => true
10
+ #
11
+ # randomize_param :q, %w{pizza restaurant flowers}
12
+ #
13
+ # randomize_param :g, %w{91106 91203}
14
+ # end
15
+ #
16
+ # compare uri3, uri4, :count => 10,
17
+ # :title => "Second Compare"
18
+ # end
19
+
20
+ class Yzma
21
+
22
+ require 'yzma/report'
23
+ require 'yzma/randomizer'
24
+
25
+
26
+ ##
27
+ # Parses ARGV for Yzma.
28
+
29
+ def self.parse_args argv
30
+ options = {:files => []}
31
+
32
+ opts = OptionParser.new do |opt|
33
+ opt.program_name = File.basename $0
34
+ opt.version = Kronk::VERSION
35
+ opt.release = nil
36
+
37
+ opt.banner = <<-STR
38
+
39
+ #{opt.program_name} #{opt.version}
40
+
41
+ Run diff reports between two URI requests.
42
+
43
+ Usage:
44
+ #{opt.program_name} --help
45
+ #{opt.program_name} --version
46
+ #{opt.program_name} file1 [file2 ...]
47
+ STR
48
+ end
49
+
50
+ opts.parse! argv
51
+
52
+ options[:files] = argv.dup
53
+
54
+ if options[:files].empty?
55
+ $stderr << "\nError: At least one report file must be specified.\n"
56
+ $stderr << "See 'yzma --help' for usage\n\n"
57
+ exit 1
58
+ end
59
+
60
+ options
61
+ end
62
+
63
+
64
+ ##
65
+ # Construct and run an Yzma report.
66
+
67
+ def self.report name_or_report=nil, &block
68
+ yzma = new name_or_report
69
+
70
+ yzma.instance_eval(&block)
71
+
72
+ yzma.report.header << "Ran #{yzma.comparisons} URI comparison(s)"
73
+ yzma.report.header << "Iterated a total of #{yzma.iterations} case(s)"
74
+
75
+ curr_req = nil
76
+
77
+ yzma.report.write do |req, data|
78
+ next unless data[:diff] > 0
79
+ "\n#{data[:diff]} avg diffs:\n#{req[0]} - #{req[1]}\n"
80
+ end
81
+ end
82
+
83
+
84
+ ##
85
+ # Run the Yzma command.
86
+
87
+ def self.run argv=ARGV
88
+ options = parse_args argv
89
+ options[:files].each do |file|
90
+ self.instance_eval File.read(file)
91
+ end
92
+
93
+ exit 2 if self.diffs > 0
94
+ end
95
+
96
+
97
+ class << self
98
+ attr_accessor :diffs
99
+ end
100
+
101
+ self.diffs = 0
102
+
103
+
104
+ attr_reader :report, :comparisons, :iterations
105
+
106
+ ##
107
+ # Initialize Izma with optional name.
108
+
109
+ def initialize name_or_report=nil
110
+ case name_or_report
111
+ when String
112
+ @name = name_or_report
113
+ @report = Report.new @name
114
+
115
+ when Report
116
+ @report = name_or_report
117
+ @name = @report.name
118
+
119
+ else
120
+ @name = 'Yzma Report'
121
+ @report = Report.new @name
122
+ end
123
+
124
+ @comparisons = 0
125
+ @iterations = 0
126
+ end
127
+
128
+
129
+ ##
130
+ # Compare two paths or uris. Second uri may be omitted.
131
+ # Supports all Kronk.compare options, plus:
132
+ # :count:: Integer - number of times to run the endpoint; default 1.
133
+ # :title:: String - title to display when running compares.
134
+
135
+ def compare uri1, uri2, options={}, &block
136
+ options = options.dup
137
+ count = options.delete(:count) || 1
138
+ title = options.delete(:title) || "#{uri1} --- #{uri2}"
139
+
140
+ @comparisons = @comparisons.next
141
+
142
+ diff_avg = 0
143
+ diff_cnt = 0
144
+
145
+ puts title
146
+ 1.upto(count) do |i|
147
+ randomizer = Randomizer.new
148
+ randomizer.instance_eval &block if block_given?
149
+
150
+ randomized_opts = options.merge randomizer.to_options
151
+
152
+ begin
153
+ diff = Kronk.compare uri1, uri2, randomized_opts
154
+
155
+ diff_avg = (diff_avg * diff_cnt + diff.count) / (diff_cnt + 1)
156
+ diff_cnt = diff_cnt.next
157
+
158
+ @iterations = @iterations.next
159
+
160
+ $stdout << (diff.count > 0 ? "D" : ".")
161
+ self.class.diffs = self.class.diffs + diff.count
162
+
163
+ rescue Kronk::Request::NotFoundError
164
+ $stdout << "E"
165
+ end
166
+
167
+ $stdout.flush
168
+ end
169
+
170
+ @report.add [uri1, uri2], :diff => diff_avg
171
+
172
+ $stdout << "\n\n"
173
+ end
174
+ end