sqltestrunner 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Guardfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/sqltestrunner +49 -0
- data/examples/creating_a_person_test.sql +33 -0
- data/lib/sql_test_runner/version.rb +3 -0
- data/lib/sql_test_runner.rb +152 -0
- data/lib/sqlite_connection.rb +33 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/sql_test_runner_spec.rb +299 -0
- data/spec/sqlite_connection_spec.rb +51 -0
- data/sqltestrunner.gemspec +27 -0
- metadata +148 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cbs
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-1.9.3-p327
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
end
|
12
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rob Westgeest
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Sqltestrunner
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sqltestrunner'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sqltestrunner
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/sqltestrunner
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.expand_path('../lib', File.dirname(__FILE__))
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'sql_test_runner'
|
6
|
+
require 'sqlite_connection'
|
7
|
+
|
8
|
+
PARSE_ERROR = 255
|
9
|
+
RUNNER_ERROR = 254
|
10
|
+
CONNECTION_ERROR = 253
|
11
|
+
|
12
|
+
module SqlTestRunner
|
13
|
+
database_options = OpenStruct.new(:database => 'sqlite', :connection => ':memory:')
|
14
|
+
|
15
|
+
option_parser = OptionParser.new do |opts|
|
16
|
+
opts.banner = "Usage #{__FILE__} [options] scriptfile"
|
17
|
+
|
18
|
+
opts.on("-d", "--database [databasetype]", "use database type (default sqlite)") do |database|
|
19
|
+
database_options.database = database
|
20
|
+
end
|
21
|
+
opts.on("-c", "--connection [connection]", "use database connection (default :memory:)") do |connection|
|
22
|
+
database_options.connection = connection
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
26
|
+
puts opts
|
27
|
+
exit(PARSE_ERROR)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
option_parser.parse!
|
31
|
+
|
32
|
+
file = ARGV.first
|
33
|
+
|
34
|
+
if file.nil?
|
35
|
+
puts option_parser
|
36
|
+
exit(PARSE_ERROR)
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
runner = Runner.new(SqliteConnection.new(database_options.connection), TestResult.new(ReportingStepLogger.new))
|
41
|
+
runner.run_file(file)
|
42
|
+
rescue ConnectionError => e
|
43
|
+
puts e.message
|
44
|
+
exit(CONNECTION_ERROR)
|
45
|
+
rescue Exception => e
|
46
|
+
puts e.message
|
47
|
+
exit(RUNNER_ERROR)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
before "creating the person table" do
|
2
|
+
execute """
|
3
|
+
CREATE TABLE IF NOT EXISTS Person(
|
4
|
+
Id INTEGER PRIMARY KEY,
|
5
|
+
Name VARCHAR(10),
|
6
|
+
Address VARCHAR(30));
|
7
|
+
"""
|
8
|
+
end
|
9
|
+
|
10
|
+
test_case "1 create a person" do
|
11
|
+
stand 0 do
|
12
|
+
execute """
|
13
|
+
INSERT INTO Person(Name, Address) VALUES('Gijs', 'Heerlen');
|
14
|
+
"""
|
15
|
+
@person_id = last_insert_id
|
16
|
+
end
|
17
|
+
|
18
|
+
stand 1 do
|
19
|
+
execute("""
|
20
|
+
SELECT Name, Address from Person WHERE Id = #{@person_id}
|
21
|
+
""").should == [
|
22
|
+
['Gijs', 'Heerlen']
|
23
|
+
]
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
test_case "silly named person" do
|
29
|
+
stand 0 do
|
30
|
+
execute "INSERT INTO Person(Name, Address) VALUES('$%$#%$#', 'Heerlen');"
|
31
|
+
execute("SELECT Name FROM Person WHERE Id = '#{last_insert_id}';i").should == [ ['$%$#%$#'] ]
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "sql_test_runner/version"
|
2
|
+
|
3
|
+
module SqlTestRunner
|
4
|
+
class Runner
|
5
|
+
def initialize(sql_connection, step_logger)
|
6
|
+
@stands = {}
|
7
|
+
@before_blocks = []
|
8
|
+
@sql_connection = sql_connection
|
9
|
+
@step_logger = step_logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_file(test_script)
|
13
|
+
begin
|
14
|
+
run File.read(test_script)
|
15
|
+
rescue Errno::ENOENT => e
|
16
|
+
raise ScriptNotFound.new(e.message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def run(test_description)
|
21
|
+
load_tests(test_description)
|
22
|
+
run_stands
|
23
|
+
step_logger.log_results
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_tests(test_description)
|
27
|
+
instance_eval test_description
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_stand(stand)
|
31
|
+
name = stand.name
|
32
|
+
stands[name] = [] unless stands[name]
|
33
|
+
stands[name] << stand
|
34
|
+
end
|
35
|
+
|
36
|
+
def before(description = "", &block)
|
37
|
+
@before_blocks << BeforeAction.new(self, description, block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_case(name, &block)
|
41
|
+
TestCase.new(self, name).instance_eval(&block)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def run_stands
|
46
|
+
before_blocks.each { |before_block| before_block.run(test_result, sql_connection, step_logger) }
|
47
|
+
stands.keys.sort.each do |key|
|
48
|
+
stands[key].each do |stand|
|
49
|
+
stand.run(test_result, sql_connection, step_logger)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
attr_reader :sql_connection, :step_logger, :stands, :before_blocks, :test_result
|
54
|
+
end
|
55
|
+
|
56
|
+
class TestResult
|
57
|
+
def initialize(logger)
|
58
|
+
@logger = logger
|
59
|
+
@errors = []
|
60
|
+
@steps_count = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def log_step(step)
|
64
|
+
@last_step = step
|
65
|
+
@steps_count += 1
|
66
|
+
logger.log_step(step)
|
67
|
+
end
|
68
|
+
|
69
|
+
def log_error(error)
|
70
|
+
error = ExpectationNotMetError.new(error, @last_step)
|
71
|
+
logger.log_error(error)
|
72
|
+
@errors << error
|
73
|
+
end
|
74
|
+
|
75
|
+
def error_count
|
76
|
+
@errors.size
|
77
|
+
end
|
78
|
+
|
79
|
+
def log_results
|
80
|
+
logger.log_results(self)
|
81
|
+
end
|
82
|
+
|
83
|
+
def summary
|
84
|
+
lines = errors.map { |error| error.summary }
|
85
|
+
lines << "#{@steps_count} testcases - #{error_count} failures"
|
86
|
+
lines.join $/
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_reader :logger, :errors
|
90
|
+
end
|
91
|
+
|
92
|
+
class TestCase < Struct.new(:runner, :name)
|
93
|
+
def stand(stand_name, &block)
|
94
|
+
runner.add_stand(Stand.new(self, stand_name, block))
|
95
|
+
end
|
96
|
+
def to_s
|
97
|
+
name
|
98
|
+
end
|
99
|
+
def description
|
100
|
+
"testcase #{name}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Step < Struct.new(:parent, :name, :block)
|
105
|
+
def run(test_result, sql_connection, step_logger)
|
106
|
+
step_logger.log_step(self)
|
107
|
+
begin
|
108
|
+
sql_connection.instance_eval(&block) if block
|
109
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
110
|
+
step_logger.log_error(e)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class Stand < Step
|
116
|
+
def description
|
117
|
+
"#{parent.description} - stand #{name}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class BeforeAction < Step
|
122
|
+
def description
|
123
|
+
"before: #{name}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class ExpectationNotMetError < Struct.new(:error, :caused_by_step)
|
128
|
+
def summary
|
129
|
+
"In #{caused_by_step.description}: #{error.message}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class ScriptNotFound < Exception
|
134
|
+
end
|
135
|
+
|
136
|
+
class ReportingStepLogger
|
137
|
+
def initialize(output = $stdout)
|
138
|
+
@output = output
|
139
|
+
end
|
140
|
+
def log_step(step)
|
141
|
+
@output.puts step.description
|
142
|
+
end
|
143
|
+
def log_error(error)
|
144
|
+
@output.puts error.summary
|
145
|
+
end
|
146
|
+
def log_results(results)
|
147
|
+
@output.puts "--- Done -- "
|
148
|
+
@output.puts "Summary:"
|
149
|
+
@output.puts results.summary
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
require 'rspec/expectations'
|
3
|
+
|
4
|
+
module SqlTestRunner
|
5
|
+
class ConnectionError < Exception
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
class SqliteConnection < Struct.new(:connection_string)
|
10
|
+
RSpec::Expectations::Syntax.enable_should(self)
|
11
|
+
|
12
|
+
def execute(query)
|
13
|
+
connection.execute(query)
|
14
|
+
end
|
15
|
+
|
16
|
+
def last_insert_id
|
17
|
+
connection.last_insert_row_id
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def connection
|
22
|
+
@connection ||= create_connection
|
23
|
+
end
|
24
|
+
def create_connection
|
25
|
+
begin
|
26
|
+
SQLite3::Database.open(connection_string)
|
27
|
+
rescue Exception => e
|
28
|
+
raise ConnectionError.new(e.message)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
$: << 'lib'
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sql_test_runner'
|
3
|
+
|
4
|
+
module SqlTestRunner
|
5
|
+
describe Runner do
|
6
|
+
let(:sql_connection) { mock('connection', :execute => nil) }
|
7
|
+
let(:step_logger) { mock('step_logger').as_null_object }
|
8
|
+
let(:result) { TestResult.new(step_logger) }
|
9
|
+
let(:runner) { Runner.new(sql_connection,result) }
|
10
|
+
|
11
|
+
describe "test cases" do
|
12
|
+
let(:sql_connection) { mock('connection') }
|
13
|
+
|
14
|
+
it "runs a stand block" do
|
15
|
+
sql_connection.should_receive(:execute).with("select bla from bla")
|
16
|
+
runner.run %Q{
|
17
|
+
test_case "name" do
|
18
|
+
stand 0 do
|
19
|
+
execute "select bla from bla"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
it "runs stand blocks of different test cases and same key in order" do
|
27
|
+
sql_connection.should_receive(:execute).with("first query of stand 0").ordered
|
28
|
+
sql_connection.should_receive(:execute).with("second query of stand 0").ordered
|
29
|
+
runner.run %Q{
|
30
|
+
test_case "name" do
|
31
|
+
stand 0 do
|
32
|
+
execute "first query of stand 0"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
test_case "other" do
|
36
|
+
stand 0 do
|
37
|
+
execute "second query of stand 0"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "runs stand blocks sorted by key" do
|
44
|
+
sql_connection.should_receive(:execute).with("query for stand 0").ordered
|
45
|
+
sql_connection.should_receive(:execute).with("query for stand 1").ordered
|
46
|
+
runner.run %Q{
|
47
|
+
test_case "name" do
|
48
|
+
stand 1 do
|
49
|
+
execute "query for stand 1"
|
50
|
+
end
|
51
|
+
stand 0 do
|
52
|
+
execute "query for stand 0"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
it "runs all sorted by key and then by test case order in file" do
|
59
|
+
sql_connection.should_receive(:execute).with("query for stand 0 of test b").ordered
|
60
|
+
sql_connection.should_receive(:execute).with("query for stand 1 of test c").ordered
|
61
|
+
sql_connection.should_receive(:execute).with("query for stand 1 of test b").ordered
|
62
|
+
runner.run %Q{
|
63
|
+
test_case "test c" do
|
64
|
+
stand 1 do
|
65
|
+
execute "query for stand 1 of test c"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
test_case "test b" do
|
69
|
+
stand 0 do
|
70
|
+
execute "query for stand 0 of test b"
|
71
|
+
end
|
72
|
+
stand 1 do
|
73
|
+
execute "query for stand 1 of test b"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "before blocks" do
|
80
|
+
it "runs a before block outside testcases as well" do
|
81
|
+
sql_connection.should_receive(:execute).with("query from before block").ordered
|
82
|
+
sql_connection.should_receive(:execute).with("query from stand 0 of testcase name").ordered
|
83
|
+
runner.run %Q{
|
84
|
+
before do
|
85
|
+
execute "query from before block"
|
86
|
+
end
|
87
|
+
test_case "name" do
|
88
|
+
stand 0 do
|
89
|
+
execute "query from stand 0 of testcase name"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
}
|
93
|
+
end
|
94
|
+
it "runs more before blocks outside testcases in order of appearence" do
|
95
|
+
sql_connection.should_receive(:execute).with("query from before block 1")
|
96
|
+
sql_connection.should_receive(:execute).with("query from before block 2").ordered
|
97
|
+
sql_connection.should_receive(:execute).with("query from stand 0 of testcase name").ordered
|
98
|
+
runner.run %Q{
|
99
|
+
before do
|
100
|
+
execute "query from before block 1"
|
101
|
+
end
|
102
|
+
before do
|
103
|
+
execute "query from before block 2"
|
104
|
+
end
|
105
|
+
test_case "name" do
|
106
|
+
stand 0 do
|
107
|
+
execute "query from stand 0 of testcase name"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
}
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "logging " do
|
117
|
+
class SimpleLoggerToString < Struct.new(:log)
|
118
|
+
def log_step(step)
|
119
|
+
log << "#{step.description}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def log_results(results)
|
123
|
+
log << results.summary
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
let(:step_logger) { SimpleLoggerToString.new(logged_strings) }
|
128
|
+
let(:logged_strings) { [] }
|
129
|
+
|
130
|
+
it "logs step" do
|
131
|
+
runner.run %Q{ test_case("name") { stand 0 } }
|
132
|
+
logged_strings.should include "testcase name - stand 0"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "logs steps for different test cases" do
|
136
|
+
runner.run %Q{
|
137
|
+
test_case("name") { stand 0 }
|
138
|
+
test_case("other") { stand 0 }
|
139
|
+
}
|
140
|
+
logged_strings[0,2].should == [
|
141
|
+
"testcase name - stand 0",
|
142
|
+
"testcase other - stand 0"
|
143
|
+
]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "logs before blocks as well" do
|
147
|
+
runner.run %Q{
|
148
|
+
before("first") {}
|
149
|
+
before("second") {}
|
150
|
+
test_case("name") { stand 0 }
|
151
|
+
}
|
152
|
+
logged_strings[0,3].should == [
|
153
|
+
"before: first",
|
154
|
+
"before: second",
|
155
|
+
"testcase name - stand 0"
|
156
|
+
]
|
157
|
+
end
|
158
|
+
|
159
|
+
it "logs results" do
|
160
|
+
runner.run %Q{}
|
161
|
+
logged_strings.should == ["0 testcases - 0 failures"]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "running a file" do
|
166
|
+
let(:script_name) { File.expand_path('example_script.sql', File.dirname(__FILE__)) }
|
167
|
+
before { create_file(script_name, 'before { execute "query" }') }
|
168
|
+
after { delete_file(script_name) }
|
169
|
+
|
170
|
+
it "runs the script" do
|
171
|
+
sql_connection.should_receive(:execute).with("query")
|
172
|
+
runner.run_file(script_name)
|
173
|
+
end
|
174
|
+
|
175
|
+
def create_file(filename, content)
|
176
|
+
delete_file(filename)
|
177
|
+
File.open(filename, "w+") { |file| file.write(content) }
|
178
|
+
end
|
179
|
+
|
180
|
+
def delete_file(filename)
|
181
|
+
File.delete(filename) if File.exists?(filename)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "expectations" do
|
186
|
+
let(:rspec_expectation_error) { create_expectation_error }
|
187
|
+
it "can compare stuff" do
|
188
|
+
runner.run %Q{ test_case("name") { stand(0) { 2.should == 2 } } }
|
189
|
+
end
|
190
|
+
|
191
|
+
it "failing compare does not raise exception" do
|
192
|
+
expect {
|
193
|
+
runner.run %Q{ test_case("name") { stand(0) { 2.should == 4 } } }
|
194
|
+
}.not_to raise_exception
|
195
|
+
end
|
196
|
+
|
197
|
+
it "failing compare adds error to list of errors" do
|
198
|
+
expect { runner.run %Q{ test_case("name") { stand(0) { 2.should == 4 } } } }.to change {result.error_count}.by(1)
|
199
|
+
result.errors.last.summary.should == "In testcase name - stand 0: #{rspec_expectation_error.message}"
|
200
|
+
end
|
201
|
+
|
202
|
+
it "failing before adds error to list of errors" do
|
203
|
+
expect { runner.run %Q{ before("description") { 2.should == 4 } } }.to change {result.error_count}.by(1)
|
204
|
+
result.errors.last.summary.should == "In before: description: #{rspec_expectation_error.message}"
|
205
|
+
end
|
206
|
+
|
207
|
+
def create_expectation_error
|
208
|
+
begin
|
209
|
+
2.should == 4
|
210
|
+
rescue Exception => e
|
211
|
+
return e
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
|
219
|
+
describe TestResult do
|
220
|
+
let(:step_logger) { mock('step_logger').as_null_object }
|
221
|
+
let(:result) { TestResult.new(step_logger) }
|
222
|
+
let(:step) { BeforeAction.new(nil, "name") }
|
223
|
+
let(:rspec_expectation_error) { create_expectation_error }
|
224
|
+
def create_expectation_error
|
225
|
+
begin
|
226
|
+
2.should == 4
|
227
|
+
rescue Exception => e
|
228
|
+
return e
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "logging step" do
|
233
|
+
|
234
|
+
it "logs the step to the logger" do
|
235
|
+
step_logger.should_receive(:log_step).with step
|
236
|
+
result.log_step(step)
|
237
|
+
end
|
238
|
+
describe "and an error" do
|
239
|
+
it "logs the error tot the logger" do
|
240
|
+
step_logger.should_receive(:log_step).with step
|
241
|
+
step_logger.should_receive(:log_error) do |error|
|
242
|
+
error.summary.should == "In before: name: #{rspec_expectation_error.message}"
|
243
|
+
end
|
244
|
+
result.log_step(step)
|
245
|
+
result.log_error(rspec_expectation_error)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "logging results" do
|
251
|
+
it "logs itself" do
|
252
|
+
step_logger.should_receive(:log_results).with result
|
253
|
+
result.log_results
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "summary" do
|
258
|
+
subject { result.summary }
|
259
|
+
it { should == "0 testcases - 0 failures" }
|
260
|
+
|
261
|
+
describe "when steps logged" do
|
262
|
+
before { result.log_step(step) }
|
263
|
+
it { should == "1 testcases - 0 failures" }
|
264
|
+
|
265
|
+
describe "and errors logged" do
|
266
|
+
before { result.log_error(rspec_expectation_error) }
|
267
|
+
it { should include "1 testcases - 1 failures" }
|
268
|
+
it { should include rspec_expectation_error.message }
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe ReportingStepLogger do
|
276
|
+
let(:output) { StringIO.new }
|
277
|
+
let(:step_logger) { ReportingStepLogger.new(output) }
|
278
|
+
describe "logging step" do
|
279
|
+
it "logs the step to the output" do
|
280
|
+
step_logger.log_step(stub('step', :description => "message"))
|
281
|
+
output.string.should include "message"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
describe "logging error" do
|
285
|
+
it "logs the error's summary to output" do
|
286
|
+
step_logger.log_error(stub('error', :summary => "message"))
|
287
|
+
output.string.should include "message"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
describe "logging results" do
|
291
|
+
it "logs the results summary to output" do
|
292
|
+
step_logger.log_results(stub('results', :summary => "message"))
|
293
|
+
output.string.should include "message"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'sqlite_connection'
|
2
|
+
|
3
|
+
module SqlTestRunner
|
4
|
+
describe SqliteConnection do
|
5
|
+
let(:connection) { SqliteConnection.new(":memory:") }
|
6
|
+
|
7
|
+
it "can execute a query" do
|
8
|
+
create_person_table.should be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can execute a query inserting a row" do
|
12
|
+
create_person_table
|
13
|
+
expect { insert_person("Gijs", "Heerlen").should == 1 }.to change{person_count}.from([[0]]).to([[1]])
|
14
|
+
end
|
15
|
+
|
16
|
+
it "read a single result" do
|
17
|
+
create_person_table
|
18
|
+
insert_person("Gijs", "Heerlen")
|
19
|
+
connection.execute("select * from Person where Id == '1';").should == [[1, "Gijs", "Heerlen"]]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "read specific columns" do
|
23
|
+
create_person_table
|
24
|
+
insert_person("Gijs", "Heerlen")
|
25
|
+
connection.execute("select Name, Address from Person where Id == '1';").first.should == ["Gijs", "Heerlen"]
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "connection error" do
|
29
|
+
let(:connection) { SqliteConnection.new('bogus_dir/bogus_connection') }
|
30
|
+
it "throws exception" do
|
31
|
+
expect { create_person_table }.to raise_exception ConnectionError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_person_table
|
36
|
+
connection.execute(%Q{CREATE TABLE IF NOT EXISTS Person(
|
37
|
+
Id INTEGER PRIMARY KEY,
|
38
|
+
Name VARCHAR(10),
|
39
|
+
Address VARCHAR(30));})
|
40
|
+
end
|
41
|
+
|
42
|
+
def insert_person(name, address)
|
43
|
+
connection.execute("INSERT INTO Person(Name, Address) VALUES('#{name}', '#{address}');")
|
44
|
+
connection.last_insert_id
|
45
|
+
end
|
46
|
+
|
47
|
+
def person_count
|
48
|
+
connection.execute("SELECT COUNT(*) from Person;")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sql_test_runner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "sqltestrunner"
|
8
|
+
gem.version = Sqltestrunner::VERSION
|
9
|
+
gem.authors = ["Rob Westgeest"]
|
10
|
+
gem.email = ["rob@qwan.it"]
|
11
|
+
gem.description = %q{runs sqltests for CBS Testing environment}
|
12
|
+
gem.summary = %q{aqltestrunner takes a _sqlt.rb file and runs the content as test
|
13
|
+
|
14
|
+
Specifically it runs blocks of testcases ordered by 'stand' blocks.
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split($/)
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
gem.add_dependency 'rspec-expectations'
|
23
|
+
gem.add_development_dependency 'rspec'
|
24
|
+
gem.add_development_dependency 'guard-rspec'
|
25
|
+
gem.add_development_dependency 'sqlite3'
|
26
|
+
gem.add_development_dependency 'rb-inotify', '0.8.8'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sqltestrunner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rob Westgeest
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec-expectations
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard-rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rb-inotify
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.8.8
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.8.8
|
94
|
+
description: runs sqltests for CBS Testing environment
|
95
|
+
email:
|
96
|
+
- rob@qwan.it
|
97
|
+
executables:
|
98
|
+
- sqltestrunner
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- .rspec
|
104
|
+
- .ruby-gemset
|
105
|
+
- .ruby-version
|
106
|
+
- Gemfile
|
107
|
+
- Guardfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- bin/sqltestrunner
|
112
|
+
- examples/creating_a_person_test.sql
|
113
|
+
- lib/sql_test_runner.rb
|
114
|
+
- lib/sql_test_runner/version.rb
|
115
|
+
- lib/sqlite_connection.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/sql_test_runner_spec.rb
|
118
|
+
- spec/sqlite_connection_spec.rb
|
119
|
+
- sqltestrunner.gemspec
|
120
|
+
homepage:
|
121
|
+
licenses: []
|
122
|
+
post_install_message:
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ! '>='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
requirements: []
|
139
|
+
rubyforge_project:
|
140
|
+
rubygems_version: 1.8.24
|
141
|
+
signing_key:
|
142
|
+
specification_version: 3
|
143
|
+
summary: aqltestrunner takes a _sqlt.rb file and runs the content as test Specifically
|
144
|
+
it runs blocks of testcases ordered by 'stand' blocks.
|
145
|
+
test_files:
|
146
|
+
- spec/spec_helper.rb
|
147
|
+
- spec/sql_test_runner_spec.rb
|
148
|
+
- spec/sqlite_connection_spec.rb
|