diff options
author | Jamis Buck <jamis@37signals.com> | 2005-01-09 15:04:16 +0000 |
---|---|---|
committer | Jamis Buck <jamis@37signals.com> | 2005-01-09 15:04:16 +0000 |
commit | c51fa9fc3d7c0ec6f59bcaf3d352fae9325857e2 (patch) | |
tree | fa6c5fdee64da937145d594348100b03225a4207 /test | |
download | third_party-sqlite3-ruby-c51fa9fc3d7c0ec6f59bcaf3d352fae9325857e2.tar.gz third_party-sqlite3-ruby-c51fa9fc3d7c0ec6f59bcaf3d352fae9325857e2.tar.xz third_party-sqlite3-ruby-c51fa9fc3d7c0ec6f59bcaf3d352fae9325857e2.zip |
Changed layout to support tagging and branching
Diffstat (limited to 'test')
-rw-r--r-- | test/bm.rb | 140 | ||||
-rw-r--r-- | test/driver/dl/tc_driver.rb | 322 | ||||
-rw-r--r-- | test/mocks.rb | 99 | ||||
-rw-r--r-- | test/native-vs-dl.rb | 126 | ||||
-rw-r--r-- | test/tc_database.rb | 216 | ||||
-rw-r--r-- | test/tc_integration.rb | 838 | ||||
-rw-r--r-- | test/tests.rb | 36 |
7 files changed, 1777 insertions, 0 deletions
diff --git a/test/bm.rb b/test/bm.rb new file mode 100644 index 0000000..aacb4a1 --- /dev/null +++ b/test/bm.rb @@ -0,0 +1,140 @@ +require 'benchmark' + +N = 1000 + +$VERBOSE=nil + +puts "file require" +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + N.times do + $".delete_if { |i| i =~ /sqlite/ } + require 'sqlite' + end + end + x.report('sqlite3') do + N.times do + $".delete_if { |i| i =~ /sqlite3/ } + require 'sqlite3' + end + end +end + +puts +puts "database creation..." +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + N.times do + File.delete "test.db" rescue nil + SQLite::Database.open( "test.db" ).close + end + end + x.report('sqlite3') do + N.times do + File.delete "test.db" rescue nil + SQLite3::Database.open( "test.db" ).close + end + end +end +File.delete "test.db" rescue nil + +SQLite::Database.open( "test.db" ).close +SQLite3::Database.open( "test3.db" ).close + +puts +puts "database open..." +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + N.times do + SQLite::Database.open( "test.db" ).close + end + end + x.report('sqlite3') do + N.times do + SQLite3::Database.open( "test3.db" ).close + end + end +end +File.delete "test.db" rescue nil +File.delete "test3.db" rescue nil + +db = SQLite::Database.open( "test.db" ) +db3 = SQLite3::Database.open( "test3.db" ) + +db.execute "create table foo (a,b)" +db3.execute "create table foo (a,b)" + +puts +puts "insertions" +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + db.transaction do + N.times do |i| + db.execute "insert into foo values (#{i}, #{i+1})" + end + end + end + x.report('sqlite3') do + db3.transaction do + N.times do |i| + db3.execute "insert into foo values (#{i}, #{i+1})" + end + end + end +end + +puts +puts "insertions using prepared statement" +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + db.transaction do + stmt = db.prepare "insert into foo values (?,?)" + N.times { |i| stmt.execute i, i+1 } + end + end + x.report('sqlite3') do + db3.transaction do + db3.prepare( "insert into foo values (?,?)" ) do |stmt| + N.times { |i| stmt.execute i, i+1 } + end + end + end +end + +db.close +db3.close +File.delete "test.db" rescue nil +File.delete "test3.db" rescue nil + +db = SQLite::Database.open( "test.db" ) +db3 = SQLite3::Database.open( "test3.db" ) + +db.execute "create table foo (a,b)" +db.execute "insert into foo values (1,2)" +db.execute "insert into foo values (3,4)" +db.execute "insert into foo values (5,6)" + +db3.execute "create table foo (a,b)" +db3.execute "insert into foo values (1,2)" +db3.execute "insert into foo values (3,4)" +db3.execute "insert into foo values (5,6)" + +puts +puts "queries" +Benchmark.bm( 7 ) do |x| + x.report('sqlite') do + N.times do + db.execute "select * from foo" + end + end + x.report('sqlite3') do + N.times do + db3.execute "select * from foo" + end + end +end + +db.close +db3.close +File.delete "test.db" rescue nil +File.delete "test3.db" rescue nil diff --git a/test/driver/dl/tc_driver.rb b/test/driver/dl/tc_driver.rb new file mode 100644 index 0000000..3dc59e3 --- /dev/null +++ b/test/driver/dl/tc_driver.rb @@ -0,0 +1,322 @@ +#-- +# ============================================================================= +# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * The names of its contributors may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +#++ + +$:.unshift "../../../lib" + +require 'sqlite3/constants' +require 'sqlite3/driver/dl/driver' +require 'test/unit' + +class TC_DL_Driver < Test::Unit::TestCase + + def utf16ify( str ) + chars = str.split(//) + chars.zip(["\0"] * chars.length).flatten.join + end + + def setup + @driver = SQLite3::Driver::DL::Driver.new + @dbname = "test.db" + @db = nil + end + + def teardown + @driver.close( @db ) rescue nil + File.delete @dbname rescue nil + end + + def test_open + result, @db = @driver.open( @dbname ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert File.exist?( @dbname ) + end + + def test_open_utf16 + name = utf16ify( @dbname ) + result, @db = @driver.open( name, true ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert File.exist?( @dbname ) + end + + def test_errmsg + result, @db = @driver.open( @dbname ) + msg = @driver.errmsg( @db ) + assert_equal msg, "not an error" + end + + def test_errmsg16 + result, @db = @driver.open( @dbname ) + msg = @driver.errmsg( @db, true ) + assert_equal msg, utf16ify( "not an error" ) + end + + def test_prepare + result, @db = @driver.open( @dbname ) + sql = "create table foo ( a, b )" + result, handle, remainder = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert_equal "", remainder + @driver.finalize( handle ) + end + + def test_prepare_error + result, @db = @driver.open( @dbname ) + sql = "create tble foo ( a, b )" + result, handle, remainder = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::ERROR, result + end + + def test_prepare_remainder + result, @db = @driver.open( @dbname ) + sql = "create table foo ( a, b ); select * from foo" + result, handle, remainder = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert_equal " select * from foo", remainder + @driver.finalize( handle ) + end + + def test_prepare16 + result, @db = @driver.open( @dbname ) + sql = utf16ify( "create table foo ( a, b )" ) + result, handle, remainder = @driver.prepare( @db, sql, true ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert_equal "", remainder + @driver.finalize( handle ) + end + + def test_prepare16_remainder + result, @db = @driver.open( @dbname ) + sql = utf16ify( "create table foo ( a, b ); select * from foo" ) + result, handle, remainder = @driver.prepare( @db, sql, true ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert_equal utf16ify( " select * from foo" ), remainder + @driver.finalize( handle ) + end + + def test_complete + assert @driver.complete?( "select * from foo;" ) + end + + def test_complete_fail + assert !@driver.complete?( "select * from foo" ) + end + + def test_complete16 + assert @driver.complete?( utf16ify("select * from foo;"), true ) + end + + def create_foo + result, @db = @driver.open( @dbname ) + sql = "create table foo ( a, b )" + result, handle, = @driver.prepare( @db, sql ) + @driver.step( handle ) + @driver.finalize( handle ) + end + + def populate_foo + create_foo + sql = "insert into foo values ( 100, 200 )" + result, handle, = @driver.prepare( @db, sql ) + @driver.step( handle ) + @driver.finalize( handle ) + end + + def test_step + populate_foo + sql = "select * from foo" + result, handle, = @driver.prepare( @db, sql ) + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + @driver.finalize( handle ) + end + + def test_step_fail + populate_foo + sql = "select * from" + result, handle, = @driver.prepare( @db, sql ) + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::MISUSE, result + @driver.finalize( handle ) + end + + def test_bind_blob + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_blob( handle, 1, "a\0b\1c\2d\0e" ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal "a\0b\1c\2d\0e", @driver.column_blob( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_double + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_double( handle, 1, 3.14 ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal 3.14, @driver.column_double( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_int + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_int( handle, 1, 14 ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal 14, @driver.column_int( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_null + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_null( handle, 1 ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal SQLite3::Constants::ColumnType::NULL, + @driver.column_type( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_text + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_text( handle, 1, "hello, world" ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal "hello, world", @driver.column_text( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_text16 + create_foo + sql = "insert into foo (b) values (?)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_text( handle, 1, utf16ify("hello, world"), true ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::DONE, result + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + sql = "select b from foo" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.step( handle ) + assert_equal SQLite3::Constants::ErrorCode::ROW, result + assert_equal "hello, world", @driver.column_text( handle, 0 ) + result = @driver.finalize( handle ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + end + + def test_bind_parameter_index + create_foo + sql = "insert into foo (b) values (:hello)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + result = @driver.bind_parameter_index( handle, ":hello" ) + assert_equal 1, result + result = @driver.bind_parameter_index( handle, ":foo" ) + assert_equal 0, result + @driver.finalize( handle ) + end + + def test_bind_parameter_name + create_foo + sql = "insert into foo (a,b) values (?,:foo)" + result, handle, = @driver.prepare( @db, sql ) + assert_equal SQLite3::Constants::ErrorCode::OK, result + assert_nil nil, @driver.bind_parameter_name(handle,1) + assert_equal ":foo", @driver.bind_parameter_name(handle,2) + @driver.finalize( handle ) + end + +end diff --git a/test/mocks.rb b/test/mocks.rb new file mode 100644 index 0000000..6843e52 --- /dev/null +++ b/test/mocks.rb @@ -0,0 +1,99 @@ +#-- +# ============================================================================= +# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * The names of its contributors may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +#++ + +require 'flexmock' + +class FlexMockWithArgs < FlexMock + attr_reader :mock_args + attr_reader :mock_blocks + + def initialize + super + @mock_args = Hash.new { |h,k| h[k] = [] } + @mock_blocks = Hash.new { |h,k| h[k] = [] } + end + + def method_missing( sym, *args, &block ) + @mock_args[sym] << args + @mock_blocks[sym] << block + super + end +end + +class Driver < FlexMockWithArgs + def self.instance + @@instance + end + + def initialize + super + @@instance = self + mock_handle( :open ) { [0,"cookie"] } + mock_handle( :close ) { 0 } + mock_handle( :complete? ) { 0 } + mock_handle( :errmsg ) { "" } + mock_handle( :errcode ) { 0 } + mock_handle( :trace ) { nil } + mock_handle( :set_authorizer ) { 0 } + mock_handle( :prepare ) { [0,"stmt", "remainder"] } + mock_handle( :finalize ) { 0 } + mock_handle( :changes ) { 14 } + mock_handle( :total_changes ) { 28 } + mock_handle( :interrupt ) { 0 } + end +end + +class Statement < FlexMockWithArgs + def self.instance + @@instance + end + + attr_reader :handle + attr_reader :sql + attr_reader :last_result + + def initialize( handle, sql ) + super() + @@instance = self + @handle = handle + @sql = sql + mock_handle( :close ) { 0 } + mock_handle( :remainder ) { "" } + mock_handle( :execute ) do + @last_result = FlexMockWithArgs.new + @last_result.mock_handle( :each ) { @last_result.mock_blocks[:each].last.call ["foo"] } + @last_result.mock_handle( :inject ) { |a,| @last_result.mock_blocks[:inject].last.call a, ["foo"] } + @last_result.mock_handle( :columns ) { ["name"] } + @last_result + end + end +end diff --git a/test/native-vs-dl.rb b/test/native-vs-dl.rb new file mode 100644 index 0000000..45e7e28 --- /dev/null +++ b/test/native-vs-dl.rb @@ -0,0 +1,126 @@ +$:.unshift "../lib", "../ext/sqlite3_api" + +require 'sqlite3' + +require 'benchmark' + +N = 1000 + +$VERBOSE=nil + +puts "database creation..." +Benchmark.bm( 7 ) do |x| + x.report('dl') do + N.times do + File.delete "test.db" rescue nil + SQLite3::Database.open( "test.db", :driver => "DL" ).close + end + end + x.report('native') do + N.times do + File.delete "test.db" rescue nil + SQLite3::Database.open( "test.db", :driver => "Native" ).close + end + end +end +File.delete "test.db" rescue nil + +SQLite3::Database.open( "test.db" ).close + +puts +puts "database open..." +Benchmark.bm( 7 ) do |x| + x.report('dl') do + N.times do + SQLite3::Database.open( "test.db", :driver => "DL" ).close + end + end + x.report('native') do + N.times do + SQLite3::Database.open( "test.db", :driver => "Native" ).close + end + end +end +File.delete "test.db" rescue nil + +dl = SQLite3::Database.open( "test-dl.db", :driver => "DL" ) +native = SQLite3::Database.open( "test-native.db", :driver => "Native" ) + +dl.execute "create table foo (a,b)" +native.execute "create table foo (a,b)" + +puts +puts "insertions" +Benchmark.bm( 7 ) do |x| + x.report('dl') do + dl.transaction do + N.times do |i| + dl.execute "insert into foo values (#{i}, #{i+1})" + end + end + end + x.report('native') do + native.transaction do + N.times do |i| + native.execute "insert into foo values (#{i}, #{i+1})" + end + end + end +end + +puts +puts "insertions using prepared statement" +Benchmark.bm( 7 ) do |x| + x.report('dl') do + dl.transaction do + dl.prepare "insert into foo values (?,?)" do |stmt| + N.times { |i| stmt.execute i, i+1 } + end + end + end + x.report('native') do + native.transaction do + native.prepare( "insert into foo values (?,?)" ) do |stmt| + N.times { |i| stmt.execute i, i+1 } + end + end + end +end + +dl.close +native.close +File.delete "test-dl.db" rescue nil +File.delete "test-native.db" rescue nil + +dl = SQLite3::Database.open( "test-dl.db", :driver => "DL" ) +native = SQLite3::Database.open( "test-native.db", :driver => "Native" ) + +dl.execute "create table foo (a,b)" +dl.execute "insert into foo values (1,2)" +dl.execute "insert into foo values (3,4)" +dl.execute "insert into foo values (5,6)" + +native.execute "create table foo (a,b)" +native.execute "insert into foo values (1,2)" +native.execute "insert into foo values (3,4)" +native.execute "insert into foo values (5,6)" + +puts +puts "queries" +Benchmark.bm( 7 ) do |x| + x.report('dl') do + N.times do + dl.execute "select * from foo" + end + end + x.report('native') do + N.times do + native.execute "select * from foo" + end + end +end + +dl.close +native.close +File.delete "test-dl.db" rescue nil +File.delete "test-native.db" rescue nil diff --git a/test/tc_database.rb b/test/tc_database.rb new file mode 100644 index 0000000..1aa2400 --- /dev/null +++ b/test/tc_database.rb @@ -0,0 +1,216 @@ +#-- +# ============================================================================= +# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * The names of its contributors may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +#++ + +$:.unshift "../lib" + +require 'sqlite3/database' +require 'test/unit' + +require 'mocks' + +class TC_Database_Init < Test::Unit::TestCase + def test_new + db = SQLite3::Database.new( "foo.db", :driver => Driver ) + assert_equal 1, Driver.instance.mock_count(:open) + assert !db.closed? + assert_equal [["foo.db",false]], Driver.instance.mock_args[:open] + assert !db.results_as_hash + assert !db.type_translation + end + + def test_open + db = SQLite3::Database.open( "foo.db", :driver => Driver ) + assert_equal 1, Driver.instance.mock_count(:open) + assert !db.closed? + assert_equal [["foo.db",false]], Driver.instance.mock_args[:open] + assert !db.results_as_hash + assert !db.type_translation + end + + def test_with_type_translation + db = SQLite3::Database.open( "foo.db", :driver => Driver, + :type_translation => true ) + assert db.type_translation + end + + def test_with_results_as_hash + db = SQLite3::Database.open( "foo.db", :driver => Driver, + :results_as_hash => true ) + assert db.results_as_hash + end + + def test_with_type_translation_and_results_as_hash + db = SQLite3::Database.open( "foo.db", :driver => Driver, + :results_as_hash => true, + :type_translation => true ) + assert db.results_as_hash + assert db.type_translation + end +end + +class TC_Database < Test::Unit::TestCase + def setup + @db = SQLite3::Database.open( "foo.db", + :driver => Driver, :statement_factory => Statement ) + end + + def test_quote + assert_equal "''one''two''three''", SQLite3::Database.quote( + "'one'two'three'" ) + end + + def test_complete + @db.complete? "foo" + assert_equal 1, Driver.instance.mock_count( :complete? ) + end + + def test_errmsg + @db.errmsg + assert_equal 1, Driver.instance.mock_count( :errmsg ) + end + + def test_errcode + @db.errcode + assert_equal 1, Driver.instance.mock_count( :errcode ) + end + + def test_translator + translator = @db.translator + assert_instance_of SQLite3::Translator, translator + end + + def test_close + @db.close + assert_equal 1, Driver.instance.mock_count( :close ) + assert @db.closed? + @db.close + assert_equal 1, Driver.instance.mock_count( :close ) + end + + def test_trace + @db.trace( 15 ) { "foo" } + driver = Driver.instance + assert_equal 1, driver.mock_count( :trace ) + assert_equal [[ "cookie", 15 ]], driver.mock_args[:trace] + assert_equal 1, driver.mock_blocks[:trace].length + end + + def test_authorizer + @db.authorizer( 15 ) { "foo" } + driver = Driver.instance + assert_equal 1, driver.mock_count( :set_authorizer ) + assert_equal [[ "cookie", 15 ]], driver.mock_args[:set_authorizer] + assert_equal 1, driver.mock_blocks[:set_authorizer].length + end + + def test_prepare_no_block + assert_nothing_raised { @db.prepare( "foo" ) } + assert_equal 0, Statement.instance.mock_count( :close ) + end + + def test_prepare_with_block + called = false + @db.prepare( "foo" ) { |stmt| called = true } + assert called + assert_equal 1, Statement.instance.mock_count( :close ) + end + + def test_execute_no_block + result = @db.execute( "foo", "bar", "baz" ) + stmt = Statement.instance + assert_equal [["foo"]], result + assert_equal [["bar", "baz"]], stmt.mock_args[:execute] + end + + def test_execute_with_block + called = false + @db.execute( "foo", "bar", "baz" ) do |row| + called = true + assert_equal ["foo"], row + end + + stmt = Statement.instance + assert called + assert_equal [["bar", "baz"]], stmt.mock_args[:execute] + end + + def test_execute2_no_block + result = @db.execute2( "foo", "bar", "baz" ) + stmt = Statement.instance + assert_equal [["name"],["foo"]], result + assert_equal [["bar", "baz"]], stmt.mock_args[:execute] + end + + def test_execute2_with_block + called = false + parts = [ ["name"],["foo"] ] + @db.execute2( "foo", "bar", "baz" ) do |row| + called = true + assert_equal parts.shift, row + end + + stmt = Statement.instance + assert called + assert_equal [["bar", "baz"]], stmt.mock_args[:execute] + end + + def test_execute_batch + @db.execute_batch( "foo", "bar", "baz" ) + stmt = Statement.instance + assert_equal [["bar", "baz"]], stmt.mock_args[:execute] + end + + def test_get_first_row + result = @db.get_first_row( "foo", "bar", "baz" ) + assert_equal ["foo"], result + end + + def test_get_first_value + result = @db.get_first_value( "foo", "bar", "baz" ) + assert_equal "foo", result + end + + def test_changes + assert_equal 14, @db.changes + assert_equal 1, Driver.instance.mock_count(:changes) + end + + def test_total_changes + assert_equal 28, @db.total_changes + assert_equal 1, Driver.instance.mock_count(:total_changes) + end + + def test_interrupt + @db.interrupt + assert_equal 1, Driver.instance.mock_count(:interrupt) + end +end diff --git a/test/tc_integration.rb b/test/tc_integration.rb new file mode 100644 index 0000000..2dd6016 --- /dev/null +++ b/test/tc_integration.rb @@ -0,0 +1,838 @@ +$:.unshift "../lib" +$:.unshift "../ext/sqlite3_api" + +require 'test/unit' +require 'benchmark' +require 'sqlite3/database' + +class String + def to_utf16 + result = "" + self.each_byte { |b| result << b.chr << "\0" } + result + end + + def from_utf16 + result = "" + length.times do |i| + result << self[i,1] if i % 2 == 0 && self[i] != 0 + end + result + end +end + +module Integration + + drivers_to_test = ( ENV["SQLITE3_DRIVERS"] || "Native" ).split(',') + drivers_to_test.each do |driver| + + # == TC_OpenClose ========================================================= + + test_case = Class.new( Test::Unit::TestCase ) do + define_method( "test_create_close" ) do + begin + db = SQLite3::Database.new( "test-create.db", + :driver => driver ) + assert File.exist?( "test-create.db" ) + assert_nothing_raised { db.close } + ensure + File.delete( "test-create.db" ) rescue nil + end + end + + define_method( "test_open_close" ) do + begin + File.open( "test-open.db", "w" ) { |f| } + assert File.exist?( "test-open.db" ) + db = SQLite3::Database.new( "test-open.db", + :driver => driver ) + assert_nothing_raised { db.close } + ensure + File.delete( "test-open.db" ) rescue nil + end + end + + define_method( "test_bad_open" ) do + assert_raise( SQLite3::CantOpenException ) do + SQLite3::Database.new( ".", :driver => driver ) + end + end + end + const_set( "TC_OpenClose_#{driver}", test_case ) + + # == TC_Database ========================================================== + + test_case = Class.new( Test::Unit::TestCase ) do + define_method( "setup" ) do + @db = SQLite3::Database.new( "test.db", :driver=>driver ) + @db.transaction do + @db.execute "create table foo ( a integer primary key, b text )" + @db.execute "insert into foo ( b ) values ( 'foo' )" + @db.execute "insert into foo ( b ) values ( 'bar' )" + @db.execute "insert into foo ( b ) values ( 'baz' )" + end + end + + define_method( "teardown" ) do + @db.close + File.delete( "test.db" ) + end + + define_method( "test_complete_fail" ) do + assert !@db.complete?( "select * from foo" ) + end + define_method( "test_complete_success" ) do + assert @db.complete?( "select * from foo;" ) + end + + define_method( "test_complete_fail_utf16" ) do + assert !@db.complete?( "select * from foo".to_utf16+"\0\0", true ) + end + define_method( "test_complete_success_utf16" ) do + assert @db.complete?( "select * from foo;".to_utf16+"\0\0", true ) + end + + define_method( "test_errmsg" ) do + assert_equal "not an error", @db.errmsg + end + + define_method( "test_errmsg_utf16" ) do + assert_equal "not an error".to_utf16, @db.errmsg(true) + end + + define_method( "test_errcode" ) do + assert_equal 0, @db.errcode + end + + define_method( "test_trace" ) do + result = nil + @db.trace( "data" ) { |data,sql| result = [ data, sql ]; 0 } + @db.execute "select * from foo" + assert_equal ["data","select * from foo"], result + end + + define_method( "test_authorizer_okay" ) do + @db.authorizer( "data" ) { |data,type,a,b,c,d| 0 } + rows = @db.execute "select * from foo" + assert_equal 3, rows.length + end + + define_method( "test_authorizer_error" ) do + @db.authorizer( "data" ) { |data,type,a,b,c,d| 1 } + assert_raise( SQLite3::AuthorizationException ) do + @db.execute "select * from foo" + end + end + + define_method( "test_authorizer_silent" ) do + @db.authorizer( "data" ) { |data,type,a,b,c,d| 2 } + rows = @db.execute "select * from foo" + assert rows.empty? + end + + define_method( "test_prepare_invalid_syntax" ) do + assert_raise( SQLite3::SQLException ) do + @db.prepare "select from foo" + end + end + + define_method( "test_prepare_invalid_column" ) do + assert_raise( SQLite3::SQLException ) do + @db.prepare "select k from foo" + end + end + + define_method( "test_prepare_invalid_table" ) do + assert_raise( SQLite3::SQLException ) do + @db.prepare "select * from barf" + end + end + + define_method( "test_prepare_no_block" ) do + stmt = @db.prepare "select * from foo" + assert stmt.respond_to?(:execute) + stmt.close + end + + define_method( "test_prepare_with_block" ) do + called = false + @db.prepare "select * from foo" do |stmt| + called = true + assert stmt.respond_to?(:execute) + end + assert called + end + + define_method( "test_execute_no_block_no_bind_no_match" ) do + rows = @db.execute( "select * from foo where a > 100" ) + assert rows.empty? + end + + define_method( "test_execute_with_block_no_bind_no_match" ) do + called = false + @db.execute( "select * from foo where a > 100" ) do |row| + called = true + end + assert !called + end + + define_method( "test_execute_no_block_with_bind_no_match" ) do + rows = @db.execute( "select * from foo where a > ?", 100 ) + assert rows.empty? + end + + define_method( "test_execute_with_block_with_bind_no_match" ) do + called = false + @db.execute( "select * from foo where a > ?", 100 ) do |row| + called = true + end + assert !called + end + + define_method( "test_execute_no_block_no_bind_with_match" ) do + rows = @db.execute( "select * from foo where a = 1" ) + assert_equal 1, rows.length + end + + define_method( "test_execute_with_block_no_bind_with_match" ) do + called = 0 + @db.execute( "select * from foo where a = 1" ) do |row| + called += 1 + end + assert_equal 1, called + end + + define_method( "test_execute_no_block_with_bind_with_match" ) do + rows = @db.execute( "select * from foo where a = ?", 1 ) + assert_equal 1, rows.length + end + + define_method( "test_execute_with_block_with_bind_with_match" ) do + called = 0 + @db.execute( "select * from foo where a = ?", 1 ) do |row| + called += 1 + end + assert_equal 1, called + end + + define_method( "test_execute2_no_block_no_bind_no_match" ) do + columns, *rows = @db.execute2( "select * from foo where a > 100" ) + assert rows.empty? + assert [ "a", "b" ], columns + end + + define_method( "test_execute2_with_block_no_bind_no_match" ) do + called = 0 + @db.execute2( "select * from foo where a > 100" ) do |row| + assert [ "a", "b" ], row unless called == 0 + called += 1 + end + assert_equal 1, called + end + + define_method( "test_execute2_no_block_with_bind_no_match" ) do + columns, *rows = @db.execute2( "select * from foo where a > ?", 100 ) + assert rows.empty? + assert [ "a", "b" ], columns + end + + define_method( "test_execute2_with_block_with_bind_no_match" ) do + called = 0 + @db.execute2( "select * from foo where a > ?", 100 ) do |row| + assert [ "a", "b" ], row unless called == 0 + called += 1 + end + assert_equal 1, called + end + + define_method( "test_execute2_no_block_no_bind_with_match" ) do + columns, *rows = @db.execute2( "select * from foo where a = 1" ) + assert_equal 1, rows.length + assert [ "a", "b" ], columns + end + + define_method( "test_execute2_with_block_no_bind_with_match" ) do + called = 0 + @db.execute2( "select * from foo where a = 1" ) do |row| + assert [ "a", "b" ], row unless called == 0 + called += 1 + end + assert_equal 2, called + end + + define_method( "test_execute2_no_block_with_bind_with_match" ) do + columns, *rows = @db.execute2( "select * from foo where a = ?", 1 ) + assert_equal 1, rows.length + assert [ "a", "b" ], columns + end + + define_method( "test_execute2_with_block_with_bind_with_match" ) do + called = 0 + @db.execute2( "select * from foo where a = ?", 1 ) do |row| + called += 1 + end + assert_equal 2, called + end + + define_method( "test_execute_batch_empty" ) do + assert_nothing_raised { @db.execute_batch "" } + end + + define_method( "test_execute_batch_no_bind" ) do + @db.transaction do + @db.execute_batch <<-SQL + create table bar ( a, b, c ); + insert into bar values ( 'one', 2, 'three' ); + insert into bar values ( 'four', 5, 'six' ); + insert into bar values ( 'seven', 8, 'nine' ); + SQL + end + rows = @db.execute( "select * from bar" ) + assert_equal 3, rows.length + end + + define_method( "test_execute_batch_with_bind" ) do + @db.execute_batch( <<-SQL, 1 ) + create table bar ( a, b, c ); + insert into bar values ( 'one', 2, ? ); + insert into bar values ( 'four', 5, ? ); + insert into bar values ( 'seven', 8, ? ); + SQL + rows = @db.execute( "select * from bar" ).map { |a,b,c| c } + assert_equal %w{1 1 1}, rows + end + + define_method( "test_get_first_row_no_bind_no_match" ) do + result = @db.get_first_row( "select * from foo where a=100" ) + assert_nil result + end + + define_method( "test_get_first_row_no_bind_with_match" ) do + result = @db.get_first_row( "select * from foo where a=1" ) + assert_equal [ "1", "foo" ], result + end + + define_method( "test_get_first_row_with_bind_no_match" ) do + result = @db.get_first_row( "select * from foo where a=?", 100 ) + assert_nil result + end + + define_method( "test_get_first_row_with_bind_with_match" ) do + result = @db.get_first_row( "select * from foo where a=?", 1 ) + assert_equal [ "1", "foo" ], result + end + + define_method( "test_get_first_value_no_bind_no_match" ) do + result = @db.get_first_value( "select b, a from foo where a=100" ) + assert_nil result + end + + define_method( "test_get_first_value_no_bind_with_match" ) do + result = @db.get_first_value( "select b, a from foo where a=1" ) + assert_equal "foo", result + end + + define_method( "test_get_first_value_with_bind_no_match" ) do + result = @db.get_first_value( "select b, a from foo where a=?", 100 ) + assert_nil result + end + + define_method( "test_get_first_value_with_bind_with_match" ) do + result = @db.get_first_value( "select b, a from foo where a=?", 1 ) + assert_equal "foo", result + end + + define_method( "test_last_insert_row_id" ) do + @db.execute "insert into foo ( b ) values ( 'test' )" + assert_equal 4, @db.last_insert_row_id + @db.execute "insert into foo ( b ) values ( 'again' )" + assert_equal 5, @db.last_insert_row_id + end + + define_method( "test_changes" ) do + @db.execute "insert into foo ( b ) values ( 'test' )" + assert_equal 1, @db.changes + @db.execute "delete from foo where 1=1" + assert_equal 4, @db.changes + end + + define_method( "test_total_changes" ) do + assert_equal 3, @db.total_changes + @db.execute "insert into foo ( b ) values ( 'test' )" + @db.execute "delete from foo where 1=1" + assert_equal 8, @db.total_changes + end + + define_method( "test_transaction_nest" ) do + assert_raise( SQLite3::SQLException ) do + @db.transaction do + @db.transaction do + end + end + end + end + + define_method( "test_transaction_rollback" ) do + @db.transaction + @db.execute_batch <<-SQL + insert into foo (b) values ( 'test1' ); + insert into foo (b) values ( 'test2' ); + insert into foo (b) values ( 'test3' ); + insert into foo (b) values ( 'test4' ); + SQL + assert_equal 7, @db.get_first_value("select count(*) from foo").to_i + @db.rollback + assert_equal 3, @db.get_first_value("select count(*) from foo").to_i + end + + define_method( "test_transaction_commit" ) do + @db.transaction + @db.execute_batch <<-SQL + insert into foo (b) values ( 'test1' ); + insert into foo (b) values ( 'test2' ); + insert into foo (b) values ( 'test3' ); + insert into foo (b) values ( 'test4' ); + SQL + assert_equal 7, @db.get_first_value("select count(*) from foo").to_i + @db.commit + assert_equal 7, @db.get_first_value("select count(*) from foo").to_i + end + + define_method( "test_transaction_rollback_in_block" ) do + assert_raise( SQLite3::SQLException ) do + @db.transaction do + @db.rollback + end + end + end + + define_method( "test_transaction_commit_in_block" ) do + assert_raise( SQLite3::SQLException ) do + @db.transaction do + @db.commit + end + end + end + + define_method( "test_transaction_active" ) do + assert !@db.transaction_active? + @db.transaction + assert @db.transaction_active? + @db.commit + assert !@db.transaction_active? + end + + define_method( "no_tests_at" ) do |file,line,method| + warn "[(#{self.class}):#{file}:#{line}] no tests for #{method}" + end + + define_method( "test_interrupt" ) do + @db.create_function( "abort", 1 ) do |func,x| + @db.interrupt + func.result = x + end + + assert_raise( SQLite3::SQLException ) do + @db.execute "select abort(a) from foo" + end + end + + define_method( "test_busy_handler_outwait" ) do + begin + db2 = SQLite3::Database.open( "test.db", :driver=>driver ) + handler_call_count = 0 + db2.busy_handler do |data,count| + handler_call_count += 1 + sleep 0.1 + 1 + end + + t = Thread.new do + @db.transaction( :exclusive ) do + sleep 0.1 + end + end + + assert_nothing_raised do + db2.execute "insert into foo (b) values ( 'from 2' )" + end + + assert_equal 1, handler_call_count + + t.join + ensure + db2.close if db2 + end + end + + define_method( "test_busy_handler_impatient" ) do + begin + db2 = SQLite3::Database.open( "test.db", :driver=>driver ) + handler_call_count = 0 + db2.busy_handler do |data,count| + handler_call_count += 1 + sleep 0.1 + 0 + end + + t = Thread.new do + @db.transaction( :exclusive ) do + sleep 0.2 + end + end + + assert_raise( SQLite3::BusyException ) do + db2.execute "insert into foo (b) values ( 'from 2' )" + end + + assert_equal 1, handler_call_count + + t.join + ensure + db2.close if db2 + end + end + + define_method( "test_busy_timeout" ) do + begin + db2 = SQLite3::Database.open( "test.db", :driver=>driver ) + db2.busy_timeout 300 + + t = Thread.new do + @db.transaction( :exclusive ) do + sleep 0.1 + end + end + + time = Benchmark.measure do + assert_raise( SQLite3::BusyException ) do + db2.execute "insert into foo (b) values ( 'from 2' )" + end + end + assert time.real*1000 >= 300 + + t.join + ensure + db2.close if db2 + end + end + + define_method( "test_create_function" ) do + @db.create_function( "munge", 1 ) do |func,x| + func.result = ">>>#{x}<<<" + end + + value = @db.get_first_value( "select munge(b) from foo where a=1" ) + assert_match( />>>.*<<</, value ) + end + + define_method( "test_create_aggregate_without_block" ) do + step = proc do |ctx,a| + ctx[:sum] ||= 0 + ctx[:sum] += a.to_i + end + + final = proc { |ctx| ctx.result = ctx[:sum] } + + @db.create_aggregate( "accumulate", 1, step, final ) + + value = @db.get_first_value( "select accumulate(a) from foo" ) + assert_equal "6", value + end + + define_method( "test_create_aggregate_with_block" ) do + @db.create_aggregate( "accumulate", 1 ) do + step do |ctx,a| + ctx[:sum] ||= 0 + ctx[:sum] += a.to_i + end + + finalize { |ctx| ctx.result = ctx[:sum] } + end + + value = @db.get_first_value( "select accumulate(a) from foo" ) + assert_equal "6", value + end + + define_method( "test_create_aggregate_with_no_data" ) do + @db.create_aggregate( "accumulate", 1 ) do + step do |ctx,a| + ctx[:sum] ||= 0 + ctx[:sum] += a.to_i + end + + finalize { |ctx| ctx.result = ctx[:sum] || 0 } + end + + value = @db.get_first_value( + "select accumulate(a) from foo where a = 100" ) + assert_equal "0", value + end + + define_method( "test_create_aggregate_handler" ) do + handler = Class.new do + class << self + define_method( "arity" ) { 1 } + define_method( "text_rep" ) { SQLite3::Constants::TextRep::ANY } + define_method( "name" ) { "multiply" } + end + define_method( "step" ) do |ctx,a| + ctx[:buffer] ||= 1 + ctx[:buffer] *= a.to_i + end + define_method( "finalize" ) { |ctx| ctx.result = ctx[:buffer] } + end + + @db.create_aggregate_handler( handler ) + value = @db.get_first_value( "select multiply(a) from foo" ) + assert_equal "6", value + end + end + const_set( "TC_Database_#{driver}", test_case ) + + # == TC_Statement ========================================================= + + test_case = Class.new( Test::Unit::TestCase ) do + define_method( "setup" ) do + @db = SQLite3::Database.new( "test.db", :driver=>driver ) + @db.transaction do + @db.execute "create table foo ( a integer primary key, b text )" + @db.execute "insert into foo ( b ) values ( 'foo' )" + @db.execute "insert into foo ( b ) values ( 'bar' )" + @db.execute "insert into foo ( b ) values ( 'baz' )" + end + @stmt = @db.prepare( "select * from foo where a in ( ?, :named )" ) + end + + define_method( "teardown" ) do + @stmt.close + @db.close + File.delete( "test.db" ) + end + + define_method( "test_remainder_empty" ) do + assert_equal "", @stmt.remainder + end + + define_method( "test_remainder_nonempty" ) do + called = false + @db.prepare( "select * from foo;\n blah" ) do |stmt| + called = true + assert_equal "\n blah", stmt.remainder + end + assert called + end + + define_method( "test_bind_params_empty" ) do + assert_nothing_raised { @stmt.bind_params } + assert @stmt.execute!.empty? + end + + define_method( "test_bind_params_array" ) do + @stmt.bind_params 1, 2 + assert_equal 2, @stmt.execute!.length + end + + define_method( "test_bind_params_hash" ) do + @stmt.bind_params ":named" => 2 + assert_equal 1, @stmt.execute!.length + end + + define_method( "test_bind_params_mixed" ) do + @stmt.bind_params( 1, ":named" => 2 ) + assert_equal 2, @stmt.execute!.length + end + + define_method( "test_bind_param_by_index" ) do + @stmt.bind_params( 1, 2 ) + assert_equal 2, @stmt.execute!.length + end + + define_method( "test_bind_param_by_name_bad" ) do + assert_raise( SQLite3::Exception ) { @stmt.bind_param( "named", 2 ) } + end + + define_method( "test_bind_param_by_name_good" ) do + @stmt.bind_param( ":named", 2 ) + assert_equal 1, @stmt.execute!.length + end + + define_method( "test_execute_no_bind_no_block" ) do + assert_instance_of SQLite3::ResultSet, @stmt.execute + end + + define_method( "test_execute_with_bind_no_block" ) do + assert_instance_of SQLite3::ResultSet, @stmt.execute( 1, 2 ) + end + + define_method( "test_execute_no_bind_with_block" ) do + called = false + @stmt.execute { |row| called = true } + assert called + end + + define_method( "test_execute_with_bind_with_block" ) do + called = 0 + @stmt.execute( 1, 2 ) { |row| called += 1 } + assert_equal 1, called + end + + define_method( "test_reexecute" ) do + r = @stmt.execute( 1, 2 ) + assert_equal 2, r.to_a.length + assert_nothing_raised { r = @stmt.execute( 1, 2 ) } + assert_equal 2, r.to_a.length + end + + define_method( "test_execute_bang_no_bind_no_block" ) do + assert @stmt.execute!.empty? + end + + define_method( "test_execute_bang_with_bind_no_block" ) do + assert_equal 2, @stmt.execute!( 1, 2 ).length + end + + define_method( "test_execute_bang_no_bind_with_block" ) do + called = 0 + @stmt.execute! { |row| called += 1 } + assert_equal 0, called + end + + define_method( "test_execute_bang_with_bind_with_block" ) do + called = 0 + @stmt.execute!( 1, 2 ) { |row| called += 1 } + assert_equal 2, called + end + + define_method( "test_columns" ) do + c1 = @stmt.columns + c2 = @stmt.columns + assert_same c1, c2 + assert_equal 2, c1.length + end + + define_method( "test_columns_computed" ) do + called = false + @db.prepare( "select count(*) from foo" ) do |stmt| + called = true + assert_equal [ "count(*)" ], stmt.columns + end + assert called + end + + define_method( "test_types" ) do + t1 = @stmt.types + t2 = @stmt.types + assert_same t1, t2 + assert_equal 2, t1.length + end + + define_method( "test_types_computed" ) do + called = false + @db.prepare( "select count(*) from foo" ) do |stmt| + called = true + assert_equal [ nil ], stmt.types + end + assert called + end + end + const_set( "TC_Statement_#{driver}", test_case ) + + # == TC_ResultSet ========================================================= + + test_case = Class.new( Test::Unit::TestCase ) do + define_method( "setup" ) do + @db = SQLite3::Database.new( "test.db", :driver=>driver ) + @db.transaction do + @db.execute "create table foo ( a integer primary key, b text )" + @db.execute "insert into foo ( b ) values ( 'foo' )" + @db.execute "insert into foo ( b ) values ( 'bar' )" + @db.execute "insert into foo ( b ) values ( 'baz' )" + end + @stmt = @db.prepare( "select * from foo where a in ( ?, ? )" ) + @result = @stmt.execute + end + + define_method( "teardown" ) do + @stmt.close + @db.close + File.delete( "test.db" ) + end + + define_method( "test_reset_unused" ) do + assert_nothing_raised { @result.reset } + assert @result.to_a.empty? + end + + define_method( "test_reset_used" ) do + @result.to_a + assert_nothing_raised { @result.reset } + assert @result.to_a.empty? + end + + define_method( "test_reset_with_bind" ) do + @result.to_a + assert_nothing_raised { @result.reset( 1, 2 ) } + assert_equal 2, @result.to_a.length + end + + define_method( "test_eof_inner" ) do + @result.reset( 1 ) + assert !@result.eof? + end + + define_method( "test_eof_edge" ) do + @result.reset( 1 ) + @result.next # to first row + @result.next # to end of result set + assert @result.eof? + end + + define_method( "test_next_eof" ) do + @result.reset( 1 ) + assert_not_nil @result.next + assert_nil @result.next + end + + define_method( "test_next_no_type_translation_no_hash" ) do + @result.reset( 1 ) + assert_equal [ "1", "foo" ], @result.next + end + + define_method( "test_next_type_translation" ) do + @db.type_translation = true + @result.reset( 1 ) + assert_equal [ 1, "foo" ], @result.next + end + + define_method( "test_next_results_as_hash" ) do + @db.results_as_hash = true + @result.reset( 1 ) + assert_equal( { "a" => "1", "b" => "foo", 0 => "1", 1 => "foo" }, + @result.next ) + end + + define_method( "test_each" ) do + called = 0 + @result.reset( 1, 2 ) + @result.each { |row| called += 1 } + assert_equal 2, called + end + + define_method( "test_enumerable" ) do + @result.reset( 1, 2 ) + assert_equal 2, @result.to_a.length + end + + define_method( "test_types" ) do + assert_equal [ "integer", "text" ], @result.types + end + + define_method( "test_columns" ) do + assert_equal [ "a", "b" ], @result.columns + end + end + const_set( "TC_ResultSet_#{driver}", test_case ) + end + +end diff --git a/test/tests.rb b/test/tests.rb new file mode 100644 index 0000000..3bded2c --- /dev/null +++ b/test/tests.rb @@ -0,0 +1,36 @@ +#-- +# ============================================================================= +# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu) +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * The names of its contributors may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# ============================================================================= +#++ + + +Dir.chdir File.dirname( __FILE__ ) +Dir["**/tc_*.rb"].each { |file| load file } |