sqltestrunner 0.0.1
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.
- 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
|