rsql 0.2.7 → 0.2.8

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,85 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+
5
+ begin
6
+ require 'rubygems'
7
+ rescue LoadError
8
+ end
9
+ require 'mocha'
10
+
11
+ $: << File.expand_path(File.join(File.dirname(__FILE__),'..','lib')) << File.dirname(__FILE__)
12
+ require 'rsql/mysql_results.rb'
13
+ require 'rsql/eval_context.rb'
14
+ require 'rsql/commands.rb'
15
+
16
+ class TestCommands < Test::Unit::TestCase
17
+
18
+ include RSQL
19
+
20
+ def setup
21
+ @orig_stdout = $stdout
22
+ $stdout = @strout = StringIO.new
23
+ @ctx = EvalContext.new
24
+ @conn = mock('Mysql')
25
+ @conn.expects(:list_dbs).returns([])
26
+ MySQLResults.conn = @conn
27
+ end
28
+
29
+ def teardown
30
+ $stdout = @orig_stdout
31
+ end
32
+
33
+ def test_simple_ruby
34
+ cmds = Commands.new('. puts :hello', :display_by_column)
35
+ assert_equal(false, cmds.empty?)
36
+ assert_not_nil(cmds.last)
37
+ cmds.run!(@ctx)
38
+ assert_equal('hello', @strout.string.chomp)
39
+ end
40
+
41
+ def test_simple_sql
42
+ cmds = Commands.new('do some silly stuff', :display_by_column)
43
+ @conn.expects(:query).with(instance_of(String)).returns(nil)
44
+ @conn.expects(:affected_rows).returns(1)
45
+ cmds.run!(@ctx)
46
+ assert_match(/Query OK, 1 row affected/, @strout.string)
47
+ end
48
+
49
+ def test_separators
50
+ cmds = Commands.new('. puts :hello\; puts :world;', :display_by_column)
51
+ cmds.run!(@ctx)
52
+ assert_equal('hello'+$/+'world', @strout.string.chomp)
53
+
54
+ # make sure our logic to handle eval'd blocks with args works
55
+ @strout.string = ''
56
+ cmds = Commands.new('. Proc.new{|a| puts a.inspect} | @results.value.call(:fancy)', :display_by_column)
57
+ cmds.run!(@ctx)
58
+ assert_equal(':fancy', @strout.string.chomp)
59
+ end
60
+
61
+ def test_multiple
62
+ @conn.expects(:query).with('one thing').returns(nil)
63
+ @conn.expects(:affected_rows).returns(1)
64
+ cmds = Commands.new('. "one thing" ; . puts :hello.inspect', :display_by_column)
65
+ cmds.run!(@ctx)
66
+ assert_match(/^QueryOK,1rowaffected\(\d+.\d+sec\):hello$/,
67
+ @strout.string.gsub(/\s+/,''))
68
+ end
69
+
70
+ def test_bangs
71
+ cmds = Commands.new('silly stuff ! this => that', :display_by_column)
72
+ @conn.expects(:query).with('silly stuff').returns(nil)
73
+ @conn.expects(:affected_rows).returns(13)
74
+ cmds.run!(@ctx)
75
+ assert_match(/Query OK, 13 rows affected/, @strout.string)
76
+
77
+ # now test logic to continue if it _doesn't_ look like a bang
78
+ cmds = Commands.new('silly stuff ! more things', :display_by_column)
79
+ @conn.expects(:query).with('silly stuff ! more things').returns(nil)
80
+ @conn.expects(:affected_rows).returns(4)
81
+ cmds.run!(@ctx)
82
+ assert_match(/Query OK, 4 rows affected/, @strout.string)
83
+ end
84
+
85
+ end # class TestCommands
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'tempfile'
5
+
6
+ begin
7
+ require 'rubygems'
8
+ rescue LoadError
9
+ end
10
+ require 'mocha'
11
+
12
+ $: << File.expand_path(File.join(File.dirname(__FILE__),'..','lib')) << File.dirname(__FILE__)
13
+ require 'rsql/mysql_results.rb'
14
+ require 'rsql/eval_context.rb'
15
+
16
+ class TestEvalContext < Test::Unit::TestCase
17
+
18
+ include RSQL
19
+
20
+ def setup
21
+ @conn = mock('Mysql')
22
+ @conn.expects(:list_dbs).returns([])
23
+ @conn.expects(:query).with(instance_of(String)).returns(nil)
24
+ @conn.expects(:affected_rows).returns(0)
25
+ MySQLResults.conn = @conn
26
+ @ctx = EvalContext.new
27
+ @ctx.load(File.join(File.dirname(__FILE__),'..','example.rsqlrc'))
28
+ end
29
+
30
+ def test_reload
31
+ orig = $stdout
32
+ $stdout = out = StringIO.new
33
+ @conn.expects(:query).with(instance_of(String)).returns(nil)
34
+ @conn.expects(:affected_rows).returns(0)
35
+ @ctx.safe_eval('reload', nil, out)
36
+ assert_match(/loaded: .+?example.rsqlrc/, out.string)
37
+ ensure
38
+ $stdout = orig
39
+ end
40
+
41
+ def test_eval
42
+ out = StringIO.new
43
+
44
+ # test a simple string registration
45
+ val = @ctx.safe_eval('cleanup_example', nil, out)
46
+ assert_equal('DROP TEMPORARY TABLE IF EXISTS rsql_example;', val)
47
+ assert_equal(true, out.string.empty?)
48
+
49
+ # test a block registration
50
+ val = @ctx.safe_eval('fill_table', nil, out)
51
+ assert_match(/(INSERT IGNORE INTO .+?){10}/, val)
52
+ assert_equal(true, out.string.empty?)
53
+
54
+ # test results handling and output redirection
55
+ res = mock
56
+ res.expects(:each_hash).yields({'value' => '2352'})
57
+ val = @ctx.safe_eval('to_report', res, out)
58
+ assert_equal(nil, val)
59
+ assert_equal("There are 1 small values and 0 big values.", out.string.chomp)
60
+ end
61
+
62
+ def test_list
63
+ out = StringIO.new
64
+ val = @ctx.safe_eval('list', nil, out)
65
+ assert_match(/usage\s+description/, out.string)
66
+ end
67
+
68
+ def test_params
69
+ val = @ctx.safe_eval('params("ft", @registrations[:fill_table].block)', nil, nil)
70
+ assert_equal('', val)
71
+ val = @ctx.safe_eval('params("sv", @registrations[:save_values].block)', nil, nil)
72
+ assert_equal('(fn)', val)
73
+ end
74
+
75
+ def test_desc
76
+ out = StringIO.new
77
+ err = StringIO.new
78
+ orig_err = $stderr
79
+
80
+ $stderr = err
81
+ val = @ctx.safe_eval('desc max_rows', nil, out)
82
+ $sterr = orig_err
83
+ assert_equal('', out.string)
84
+ assert_equal('refusing to describe EvalContext#max_rows',
85
+ err.string.chomp)
86
+
87
+ err.string = ''
88
+ $stderr = err
89
+ val = @ctx.safe_eval('desc :sldkfjas', nil, out)
90
+ $sterr = orig_err
91
+ assert_equal('', out.string)
92
+ assert_equal('nothing registered as sldkfjas', err.string.chomp)
93
+
94
+ err.string = ''
95
+ $stderr = err
96
+ val = @ctx.safe_eval('desc :version', nil, out)
97
+ $sterr = orig_err
98
+ assert_equal('', out.string)
99
+ assert_equal('refusing to describe the version method', err.string.chomp)
100
+
101
+ err.string = ''
102
+ out.string = ''
103
+ val = @ctx.safe_eval('desc :cleanup_example', nil, out)
104
+ assert_equal('', err.string)
105
+ assert_match(
106
+ /^\s*\[.+\/example.rsqlrc:\d+\]\s+DROP TEMPORARY TABLE IF EXISTS \#\{@rsql_table\}\s*$/,
107
+ out.string)
108
+
109
+ out.string = ''
110
+ val = @ctx.safe_eval('desc :to_report', nil, out)
111
+ lines = out.string.split($/).select{|l|l.any?}
112
+ assert_match(/^\[.+\/example.rsqlrc:\d+\]$/, lines[0])
113
+ assert_match(/^register .+ do$/, lines[1])
114
+ assert_match(/^\s+puts/, lines[-2])
115
+ assert_match(/^end$/, lines[-1])
116
+ assert_equal(13, lines.size)
117
+ end
118
+
119
+ def test_complete
120
+ out = @ctx.complete('')
121
+ assert_equal(20, out.size, out.inspect)
122
+ assert_equal(['version'], @ctx.complete('v'))
123
+ assert_equal(['.version'], @ctx.complete('.v'))
124
+ end
125
+
126
+ def test_bang_eval
127
+ @ctx.bangs = {'time' => :relative_time}
128
+ t = (Time.now - 2532435).to_s
129
+ assert_equal(t, @ctx.bang_eval('do no harm', t))
130
+ assert_equal(' 29 days ago', @ctx.bang_eval('time', t))
131
+ end
132
+
133
+ def test_humanize
134
+ out = StringIO.new
135
+ assert_equal(' 9.16 GB',
136
+ @ctx.safe_eval('humanize_bytes(9832742324)', nil, out))
137
+ assert_equal(9835475108,
138
+ @ctx.safe_eval('dehumanize_bytes(" 9.16 GB")', nil, out))
139
+ assert_equal(' 20.9%',
140
+ @ctx.safe_eval('humanize_percentage(0.209384)', nil, out))
141
+ assert(out.string.empty?)
142
+ end
143
+
144
+ def test_hex
145
+ bin = ''
146
+ 100.times{|i| bin << i}
147
+ hex = @ctx.to_hexstr(bin)
148
+ assert_equal('0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f' <<
149
+ '... (68 bytes hidden)', hex)
150
+
151
+ out = StringIO.new
152
+ assert_equal('0x1234', @ctx.safe_eval('hexify("1234")', nil, out))
153
+ assert_equal('0x1234', @ctx.safe_eval('hexify("0x1234")', nil, out))
154
+ assert_equal('0x1234', @ctx.safe_eval('hexify(0x1234)', nil, out))
155
+ assert(out.string.empty?)
156
+ end
157
+
158
+ def test_safe_save
159
+ out = StringIO.new
160
+ @ctx.safe_eval('@mystuff = {:one => 1, :two => 2}', nil, out)
161
+ tf = Tempfile.new('mystuff')
162
+ @ctx.safe_eval("safe_save(@mystuff, '#{tf.path}')", nil, out)
163
+ tf = tf.path + '.yml'
164
+ assert_equal("Saved: #{tf}", out.string.chomp)
165
+ assert_equal({:one => 1, :two => 2}, YAML.load_file(tf))
166
+
167
+ # now make sure it keeps one backup copy
168
+ out = StringIO.new
169
+ @ctx.safe_eval('@mystuff = {:one => 1}', nil, out)
170
+ @ctx.safe_eval("safe_save(@mystuff, '#{tf}')", nil, out)
171
+ assert_equal("Saved: #{tf}", out.string.chomp)
172
+ assert_equal({:one => 1}, YAML.load_file(tf))
173
+ assert_equal({:one => 1, :two => 2}, YAML.load_file(tf+'~'))
174
+ ensure
175
+ File.unlink(tf) if File.exists?(tf)
176
+ File.unlink(tf+'~') if File.exists?(tf+'~')
177
+ end
178
+
179
+ end # class TestEvalContext
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+
5
+ begin
6
+ require 'rubygems'
7
+ rescue LoadError
8
+ end
9
+ require 'mocha'
10
+
11
+ $: << File.expand_path(File.join(File.dirname(__FILE__),'..','lib')) << File.dirname(__FILE__)
12
+ require 'rsql/mysql_results.rb'
13
+
14
+ class TestMySQLResults < Test::Unit::TestCase
15
+
16
+ include RSQL
17
+
18
+ def setup
19
+ MySQLResults.conn = nil
20
+ MySQLResults.database_name = nil
21
+ MySQLResults.reset_cache
22
+ end
23
+
24
+ def test_databases
25
+ assert_equal([], MySQLResults.databases)
26
+ conn = mock('Mysql')
27
+ conn.expects(:list_dbs).returns(['accounts'])
28
+ conn.expects(:select_db)
29
+ conn.expects(:list_tables).returns([])
30
+ MySQLResults.conn = conn
31
+ assert_equal(['accounts'], MySQLResults.databases)
32
+ end
33
+
34
+ def test_tables
35
+ assert_equal([], MySQLResults.tables)
36
+ MySQLResults.reset_cache
37
+
38
+ conn = mock('Mysql')
39
+ conn.expects(:list_dbs).returns(['accounts'])
40
+ conn.expects(:select_db)
41
+ conn.expects(:list_tables).returns(['users','groups'])
42
+ MySQLResults.conn = conn
43
+
44
+ assert_equal([], MySQLResults.tables)
45
+ MySQLResults.database_name = 'accounts'
46
+ assert_equal(['groups','users'], MySQLResults.tables)
47
+ assert_equal(['groups','users'], MySQLResults.tables('accounts'))
48
+ end
49
+
50
+ def test_complete
51
+ assert_equal([], MySQLResults.complete(nil))
52
+
53
+ conn = mock('Mysql')
54
+ conn.expects(:list_dbs).returns(['Accounts','Devices','Locations'])
55
+ conn.expects(:select_db).times(3)
56
+ tbls = sequence(:tbls)
57
+ conn.expects(:list_tables).in_sequence(tbls).returns(['Prefs','Names'])
58
+ conn.expects(:list_tables).in_sequence(tbls).returns(['IPs'])
59
+ conn.expects(:list_tables).in_sequence(tbls).returns(['Street','City','State'])
60
+ MySQLResults.conn = conn
61
+
62
+ assert_equal(['Accounts','Devices','Locations'], MySQLResults.complete(''))
63
+ assert_equal(['Accounts'], MySQLResults.complete('a'))
64
+
65
+ MySQLResults.database_name = 'Accounts'
66
+ assert_equal(['Devices','Locations','Names','Prefs'], MySQLResults.complete(''))
67
+ assert_equal(['Names'], MySQLResults.complete('n'))
68
+
69
+ assert_equal(['Accounts.Names','Accounts.Prefs'], MySQLResults.complete('accounts.'))
70
+ end
71
+
72
+ def test_query
73
+ f1 = mock('f1')
74
+ f1.expects(:name).returns('c1').times(12)
75
+ f1.expects(:type).returns(1).times(2)
76
+ f2 = mock('f2')
77
+ f2.expects(:name).returns('c2').times(11)
78
+ f2.expects(:type).returns(1).times(2)
79
+
80
+ res = mock('results')
81
+ res.expects(:num_rows).returns(2).times(2)
82
+ res.expects(:fetch_fields).returns([f1,f2])
83
+
84
+ rows = sequence(:rows)
85
+ res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
86
+ res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
87
+ res.expects(:fetch_row).in_sequence(rows).returns(nil)
88
+
89
+ conn = mock('Mysql')
90
+ conn.expects(:list_dbs).returns([])
91
+ conn.expects(:query).with(instance_of(String)).returns(res)
92
+ conn.expects(:affected_rows).returns(1)
93
+ MySQLResults.conn = conn
94
+
95
+ bangs = mock('bangs')
96
+ bangs.expects(:bang_eval).with(instance_of(String),instance_of(String)).
97
+ returns('val').times(4)
98
+
99
+ mres = MySQLResults.query('ignored', bangs)
100
+ assert_equal('ignored', mres.sql)
101
+ assert_equal(true, mres.any?)
102
+ assert_equal(false, mres.empty?)
103
+ assert_equal(2, mres.num_rows)
104
+ assert_equal({"c1"=>"val", "c2"=>"val"}, mres[0])
105
+ assert_equal({"c1"=>"val", "c2"=>"val"}, mres[1])
106
+ assert_equal(nil, mres[2])
107
+
108
+ cnt = 0
109
+ mres.each_hash do |row|
110
+ cnt += 1
111
+ assert_equal({"c1"=>"val", "c2"=>"val"}, row)
112
+ end
113
+ assert_equal(2, cnt)
114
+
115
+ dout = StringIO.new
116
+ mres.display_by_column(dout)
117
+ assert_match(/^c1c2--------valvalvalval--------2rowsinset/,
118
+ dout.string.gsub(/\s+/,''))
119
+
120
+ dout = StringIO.new
121
+ mres.display_by_batch(dout)
122
+ assert_equal('valvalvalval', dout.string.gsub(/\s+/,''))
123
+
124
+ dout = StringIO.new
125
+ mres.display_by_line(dout)
126
+ assert_match(/^\*+1.row\*+c1:valc2:val\*+2.row\*+c1:valc2:val2rowsinset/,
127
+ dout.string.gsub(/\s+/,''))
128
+ end
129
+
130
+ def test_grep
131
+ f1 = mock('f1')
132
+ f1.stubs(:name).returns('c1')
133
+ f1.stubs(:type).returns(1)
134
+ f2 = mock('f2')
135
+ f2.stubs(:name).returns('c2')
136
+ f2.stubs(:type).returns(1)
137
+
138
+ res = mock('results')
139
+ res.stubs(:num_rows).returns(2)
140
+ res.stubs(:fetch_fields).returns([f1,f2])
141
+
142
+ rows = sequence(:rows)
143
+ res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
144
+ res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
145
+ res.expects(:fetch_row).in_sequence(rows).returns(nil)
146
+
147
+ conn = mock('Mysql')
148
+ conn.stubs(:list_dbs).returns([])
149
+ conn.stubs(:query).with(instance_of(String)).returns(res)
150
+ conn.stubs(:affected_rows).returns(1)
151
+ MySQLResults.reset_history
152
+ MySQLResults.conn = conn
153
+
154
+ mres = MySQLResults.query('ignored1', eval_context=nil, raw=true)
155
+ assert_equal(false, mres.grep(/val/))
156
+
157
+ rows = sequence(:rows)
158
+ res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
159
+ res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
160
+ res.expects(:fetch_row).in_sequence(rows).returns(nil)
161
+
162
+ mres = MySQLResults.query('ignored2', eval_context=nil, raw=true)
163
+ assert_equal(true, mres.grep('v1', :fixed))
164
+ assert_equal("\e[31;1mv1\e[0m.1", mres[0]['c1'])
165
+ assert_equal("\e[31;1mv1\e[0m.2", mres[0]['c2'])
166
+
167
+ rows = sequence(:rows)
168
+ res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
169
+ res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
170
+ res.expects(:fetch_row).in_sequence(rows).returns(nil)
171
+
172
+ mres = MySQLResults.query('ignored3', eval_context=nil, raw=true)
173
+ assert_equal(false, mres.grep('v', :fixed, :inverse))
174
+
175
+ rows = sequence(:rows)
176
+ res.expects(:fetch_row).in_sequence(rows).returns(['v1.1','v1.2'])
177
+ res.expects(:fetch_row).in_sequence(rows).returns(['v2.1','v2.2'])
178
+ res.expects(:fetch_row).in_sequence(rows).returns(nil)
179
+
180
+ mres = MySQLResults.query('ignored4', eval_context=nil, raw=true)
181
+ assert_equal(true, mres.grep('v1.1', :nocolor))
182
+ assert_equal("v1.1", mres[0]['c1'])
183
+
184
+ # fixme: technically should be in it's only test...
185
+ cmds = []
186
+ 4.times{|i| cmds << "ignored#{i+1}"}
187
+ assert_equal(cmds, MySQLResults.history)
188
+ assert_equal([cmds.last], MySQLResults.history(1))
189
+ assert_equal(cmds, MySQLResults.history(15))
190
+ end
191
+
192
+ end # class TestMySQLResults