kronk 1.2.5 → 1.3.0

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.
@@ -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