diff --git a/.gitignore b/.gitignore index 6611613..4aee434 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ - +Gemfile.lock *.swp *.gem *.so diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..feba68d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,27 @@ +.base: &base + variables: + RAKE_VERSION: 10.4.2 + before_script: + - apt-get update && apt-get install -y debconf-utils git-core + - echo "firebird2.5-super shared/firebird/sysdba_password/new_password password masterkey" | debconf-set-selections + - DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential patch ruby-dev zlib1g-dev liblzma-dev firebird-dev firebird2.5-super + - service firebird2.5-super start + - gem install bundler && bundle + script: + - bundle exec rake compile:fb_ext test + +ruby-1.9.3: + <<: *base + image: zedtux/ruby-1.9.3:latest + +ruby-2.2: + <<: *base + image: ruby:2.2-jessie + +ruby-2.3: + <<: *base + image: ruby:2.3-jessie + +ruby-2.4: + <<: *base + image: ruby:2.4-jessie diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..aa96f57 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +language: ruby +install: + - sudo apt-get update + # && sudo apt-get install debconf-utils + # - echo "firebird2.5-super shared/firebird/sysdba_password/new_password password masterkey" | sudo debconf-set-selections + - sudo apt-get install -y build-essential patch ruby-dev zlib1g-dev liblzma-dev firebird-dev firebird2.5-super + - bundle +before_script: + - export ISC_PASSWORD=$(sudo grep ISC_PASSWORD /etc/firebird/2.5/SYSDBA.password | ruby -e "puts STDIN.read.split(/[=\"]/)[2]") + - echo "modify sysdba -pw masterkey" | gsec -user SYSDBA -password $ISC_PASSWORD + - sudo mkdir -p /tmp/firebird + - sudo chown firebird.firebird /tmp/firebird + - sudo chmod 0777 /tmp/firebird +script: + - bundle exec rake compile:fb_ext test +rvm: + - 1.9.3 + - 2.0.0 + - 2.1 + - 2.2 + - 2.3 + - 2.4 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..814690c --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source 'http://rubygems.org' +gemspec \ No newline at end of file diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 5a92699..0000000 --- a/MANIFEST +++ /dev/null @@ -1,14 +0,0 @@ -MANIFEST -README -extconf.rb -fb.c -mkmf.cmd -fb.gemspec -test -test\ConnectionTestCases.rb -test\CursorTestCases.rb -test\DatabaseTestCases.rb -test\DataTypesTestCases.rb -test\FbTestCases.rb -test\FbTestSuite.rb -test\TransactionTestCases.rb diff --git a/README.md b/README.md new file mode 100644 index 0000000..6f6757d --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Fb - Ruby Firebird Extension Library + +[![Build Status](https://travis-ci.org/rowland/fb.svg?branch=master)](https://travis-ci.org/rowland/fb) + +This is a Ruby driver for the [Firebird](https://firebirdsql.org/) database. + +# Sample usage + +* See the [API Documentation](http://www.rubydoc.info/github/rowland/fb) +* See [USAGE.txt](USAGE.txt) for a brief tutorial on the usage. + +# Running Tests + + bundle exec rake compile:fb_ext + bundle exec rake diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..e9371ff --- /dev/null +++ b/Rakefile @@ -0,0 +1,13 @@ +require "rake/testtask" +require "rake/extensiontask" + +Rake::ExtensionTask.new "fb_ext" do |ext| + ext.ext_dir = 'ext/fb' + ext.lib_dir = 'lib/fb' +end + +Rake::TestTask.new do |t| + t.test_files = FileList['test/**/*.rb'] - FileList['test/test_helper.rb'] +end + +task :default => :test diff --git a/README b/USAGE.txt similarity index 100% rename from README rename to USAGE.txt diff --git a/extconf.rb b/ext/fb/extconf.rb similarity index 99% rename from extconf.rb rename to ext/fb/extconf.rb index abd3978..7d221a7 100644 --- a/extconf.rb +++ b/ext/fb/extconf.rb @@ -90,4 +90,4 @@ def search_firebird_path libs.find {|lib| have_library(lib, test_func) } end -create_makefile("fb") +create_makefile("fb_ext") diff --git a/fb.c b/ext/fb/fb_ext.c similarity index 99% rename from fb.c rename to ext/fb/fb_ext.c index 99b352f..5f4df14 100644 --- a/fb.c +++ b/ext/fb/fb_ext.c @@ -148,7 +148,7 @@ typedef struct trans_opts #define UPPER(c) (((c) >= 'a' && (c)<= 'z') ? (c) - 'a' + 'A' : (c)) #define FREE(p) if (p) { xfree(p); p = 0; } #define SETNULL(p) if (p && strlen(p) == 0) { p = 0; } - // #define HERE(s) printf("%s\n", s) + // #define HERE(s) printf("%s\n", s) #define HERE(s) static long calculate_buffsize(XSQLDA *sqlda) @@ -255,13 +255,13 @@ static VALUE fb_mkdate(struct tm *tm) { return rb_funcall( rb_cDate, rb_intern("civil"), 3, - INT2FIX(1900 + tm->tm_year), INT2FIX(tm->tm_mon + 1), INT2FIX(tm->tm_mday)); + INT2FIX(1900 + tm->tm_year), INT2FIX(tm->tm_mon + 1), INT2FIX(tm->tm_mday)); } static int responds_like_date(VALUE obj) { - return rb_respond_to(obj, rb_intern("year")) && - rb_respond_to(obj, rb_intern("month")) && + return rb_respond_to(obj, rb_intern("year")) && + rb_respond_to(obj, rb_intern("month")) && rb_respond_to(obj, rb_intern("day")); } static void tm_from_date(struct tm *tm, VALUE date) @@ -1532,7 +1532,7 @@ static void fb_cursor_set_inputparams(struct FbCursor *fb_cursor, long argc, VAL offset = FB_ALIGN(offset, alignment); var->sqldata = (char *)(fb_cursor->i_buffer + offset); *(bool *)var->sqldata = obj; - offset += alignment; + offset += alignment; break; #endif default : @@ -1809,7 +1809,7 @@ static VALUE fb_cursor_fetch(struct FbCursor *fb_cursor) dtp = var->sqltype & ~1; /* Check if column is null */ - + if ((var->sqltype & 1) && (*var->sqlind < 0)) { val = Qnil; @@ -2937,7 +2937,7 @@ static VALUE database_s_drop(int argc, VALUE *argv, VALUE klass) return database_drop(obj); } -void Init_fb() +void Init_fb_ext() { rb_funcall(rb_mKernel, rb_intern("require"), 1, rb_str_new2("bigdecimal")); diff --git a/fb.gemspec b/fb.gemspec index 5509675..f81575d 100644 --- a/fb.gemspec +++ b/fb.gemspec @@ -1,26 +1,34 @@ -require 'rubygems' +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'fb/version' Gem::Specification.new do |s| s.name = "fb" - s.version = "0.9.0" - s.date = "2018-01-10" + s.version = Fb::VERSION + s.date = "2018-03-04" s.summary = "Firebird database driver" s.description = "Ruby Firebird Extension Library" s.licenses = ["MIT"] s.requirements = "Firebird client library fbclient.dll, libfbclient.so or Firebird.framework." - s.require_path = '.' + s.require_paths = ["lib", "ext"] s.author = "Brent Rowland" s.email = "rowland@rowlandresearch.com" s.homepage = "http://github.com/rowland/fb" - s.test_file = "test/FbTestSuite.rb" - s.has_rdoc = true - s.extra_rdoc_files = ['README'] - s.rdoc_options << '--title' << 'Fb -- Ruby Firebird Extension' << '--main' << 'README' << '-x' << 'test' - s.files = ['extconf.rb', 'fb.c', 'README', 'fb_extensions.rb'] + Dir.glob("test/*.rb") + # s.has_rdoc = true + # s.extra_rdoc_files = ['README'] + # s.rdoc_options << '--title' << 'Fb -- Ruby Firebird Extension' << '--main' << 'README' << '-x' << 'test' + # s.files = ['ext/fb/extconf.rb', 'ext/fb/fb.c', 'README', 'lib/fb.rb'] + Dir.glob("test/*.rb") + s.files = `git ls-files`.split($/) s.platform = case RUBY_PLATFORM when /win32/ then Gem::Platform::WIN32 else Gem::Platform::RUBY end - s.extensions = ['extconf.rb'] if s.platform == Gem::Platform::RUBY + s.extensions = ['ext/fb/extconf.rb'] if s.platform == Gem::Platform::RUBY + s.add_development_dependency "rake", ">= 0" + s.add_development_dependency "rake-compiler", ">= 0" + if RUBY_VERSION =~ /^2/ + s.add_development_dependency "minitest", ">= 0" + end end diff --git a/fb_extensions.rb b/lib/fb.rb similarity index 95% rename from fb_extensions.rb rename to lib/fb.rb index 3fc3e4f..34126c4 100644 --- a/fb_extensions.rb +++ b/lib/fb.rb @@ -1,3 +1,5 @@ +require 'fb/fb_ext' + module Fb class Connection def execute_script(sql) diff --git a/lib/fb/version.rb b/lib/fb/version.rb new file mode 100644 index 0000000..ff99598 --- /dev/null +++ b/lib/fb/version.rb @@ -0,0 +1,3 @@ +module Fb + VERSION = "0.10.0" +end diff --git a/test/ConnectionTestCases.rb b/test/ConnectionTestCases.rb index 5e5e64e..4de290c 100644 --- a/test/ConnectionTestCases.rb +++ b/test/ConnectionTestCases.rb @@ -1,8 +1,6 @@ -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class ConnectionTestCases < FbTestCase - include FbTestCases - def test_execute sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))" sql_select = "SELECT * FROM RDB$DATABASE" @@ -16,11 +14,11 @@ def test_execute connection.drop end end - + def test_query_select sql_select = "SELECT * FROM RDB$DATABASE" Database.create(@parms) do |connection| - + d = connection.query(sql_select) assert_instance_of Array, d assert_equal 1, d.size @@ -30,7 +28,7 @@ def test_query_select else assert_equal 4, d.first.size end - + a = connection.query(:array, sql_select) assert_instance_of Array, a assert_equal 1, a.size @@ -59,7 +57,7 @@ def test_query_select end end end - + def test_query_update sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20))" sql_insert = "INSERT INTO TEST (ID, NAME) VALUES (?, ?)" @@ -68,30 +66,30 @@ def test_query_update sql_select = "SELECT * FROM TEST" Database.create(@parms) do |connection| su = connection.query(sql_schema) - assert_equal -1, su - + assert_equal(-1, su) + i = connection.query(sql_insert, 1, "NAME") assert_equal 1, i - + u = connection.query(sql_update, 1, "NAME2", 1) assert_equal 1, u - + d = connection.query(sql_delete, 1) assert_equal 1, d - + q = connection.query(sql_select) assert_instance_of Array, q assert_equal 0, q.size end end - + def test_insert_blobs_text sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20), MEMO BLOB SUB_TYPE TEXT)" sql_insert = "INSERT INTO TEST (ID, NAME, MEMO) VALUES (?, ?, ?)" sql_select = "SELECT * FROM TEST ORDER BY ID" Database.create(@parms) do |connection| connection.execute(sql_schema); - memo = IO.read("fb.c") + memo = "x" * 65535 assert memo.size > 50000 connection.transaction do 10.times do |i| @@ -115,13 +113,9 @@ def test_insert_blobs_binary sql_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20), ATTACHMENT BLOB SEGMENT SIZE 1000)" sql_insert = "INSERT INTO TEST (ID, NAME, ATTACHMENT) VALUES (?, ?, ?)" sql_select = "SELECT * FROM TEST ORDER BY ID" - filename = "fb.c" Database.create(@parms) do |connection| connection.execute(sql_schema); - attachment = File.open(filename,"rb") do |f| - f.read * 3 - end - assert (attachment.size > 150000), "Not expected size" + attachment = SecureRandom.random_bytes(250_000) connection.transaction do 3.times do |i| connection.execute(sql_insert, i, i.to_s, attachment); @@ -187,13 +181,13 @@ def test_multi_insert end def test_dialects - db = Database.create(@parms) do |connection| + Database.create(@parms) do |connection| assert_equal 3, connection.dialect assert_equal 3, connection.db_dialect connection.drop end end - + def test_open? db = Database.create(@parms); connection = db.connect @@ -202,7 +196,7 @@ def test_open? assert !connection.open? db.drop end - + def test_properties_instance db = Database.new(@parms) db.create @@ -215,7 +209,7 @@ def test_properties_instance connection.drop end end - + def test_properties_singleton Database.create(@parms) do |connection| assert_equal @parms[:database], connection.database @@ -226,25 +220,25 @@ def test_properties_singleton connection.drop end end - + def test_drop_instance db = Database.create(@parms) - assert File.exists?(@db_file) + assert File.exist?(@db_file) connection = db.connect - assert connection.open? + assert connection.open? connection.drop assert !connection.open? - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) end - + def test_drop_singleton Database.create(@parms) do |connection| - assert File.exists?(@db_file) + assert File.exist?(@db_file) connection.drop - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) end end - + def test_to_s db = Database.new(@parms) db.create @@ -256,7 +250,7 @@ def test_to_s assert_equal "#{@parms[:database]} (CLOSED)", connection.to_s end end - + def test_table_names sql_schema = <<-END CREATE TABLE TEST1 (ID INT); @@ -351,7 +345,7 @@ def test_role_names assert_equal 'WRITER', names[1] end end - + def test_role_names_downcased sql_schema = <<-END create role reader; @@ -364,7 +358,7 @@ def test_role_names_downcased assert_equal 'writer', names[1] end end - + def test_procedure_names sql_schema = <<-END_SQL CREATE PROCEDURE PLUSONE(NUM1 INTEGER) RETURNS (NUM2 INTEGER) AS @@ -394,7 +388,7 @@ def test_procedure_names_downcased assert_equal 'plusone', names[0] end end - + def test_trigger_names table_schema = "CREATE TABLE TEST (ID INT, NAME VARCHAR(20)); CREATE GENERATOR TEST_SEQ;" trigger_schema = <<-END_SQL @@ -448,16 +442,16 @@ def test_index_names assert indexes.keys.include?('FK_DETAIL_MASTER_ID') assert indexes.keys.include?('IX_MASTER_NAME1') assert indexes.keys.include?('IX_DETAIL_ID_DESC') - + assert indexes['PK_MASTER'].columns.include?('ID') assert indexes['PK_DETAIL'].columns.include?('ID') master_indexes = indexes.values.select {|ix| ix.table_name == 'MASTER' } assert_equal 2, master_indexes.size - + detail_indexes = indexes.values.select {|ix| ix.table_name == 'DETAIL' } assert_equal 3, detail_indexes.size - + assert_equal 'MASTER', indexes['PK_MASTER'].table_name assert indexes['PK_MASTER'].unique assert !indexes['PK_MASTER'].descending @@ -465,7 +459,7 @@ def test_index_names assert_equal 'MASTER', indexes['IX_MASTER_NAME1'].table_name assert indexes['IX_MASTER_NAME1'].unique assert !indexes['IX_MASTER_NAME1'].descending - + assert_equal 'DETAIL', indexes['PK_DETAIL'].table_name assert indexes['PK_DETAIL'].unique assert !indexes['PK_DETAIL'].descending @@ -476,8 +470,8 @@ def test_index_names assert_equal 'DETAIL', indexes['IX_DETAIL_ID_DESC'].table_name assert !indexes['IX_DETAIL_ID_DESC'].unique - assert indexes['IX_DETAIL_ID_DESC'].descending - + assert indexes['IX_DETAIL_ID_DESC'].descending + connection.drop end end @@ -514,7 +508,7 @@ def test_columns I INTEGER, SI SMALLINT, BI BIGINT, - F FLOAT, + F FLOAT, D DOUBLE PRECISION, C CHAR, C10 CHAR(10), @@ -552,5 +546,5 @@ def test_columns assert_equal column, columns[i] end end - end + end end diff --git a/test/CursorTestCases.rb b/test/CursorTestCases.rb index c30c139..6f866e4 100644 --- a/test/CursorTestCases.rb +++ b/test/CursorTestCases.rb @@ -1,8 +1,6 @@ -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class CursorTestCases < FbTestCase - include FbTestCases - def test_fetch_array Database.create(@parms) do |connection| connection.execute("select * from rdb$database") do |cursor| @@ -218,7 +216,7 @@ def test_fetch_after_nil r2 = cursor.fetch assert_nil r2 assert_raises Error do - r3 = cursor.fetch + cursor.fetch end end connection.execute("select * from rdb$database") do |cursor| @@ -227,7 +225,7 @@ def test_fetch_after_nil r2 = cursor.fetch assert_nil r2 assert_raises Error do - r3 = cursor.fetch + cursor.fetch end end connection.drop @@ -250,7 +248,7 @@ def test_fetch_hash_with_aliased_fields connection.drop end end - + def test_simultaneous_cursors sql_schema = <<-END CREATE TABLE MASTER (ID INT, NAME1 VARCHAR(10)); diff --git a/test/DataTypesTestCases.rb b/test/DataTypesTestCases.rb index cc452fa..f62ebd5 100644 --- a/test/DataTypesTestCases.rb +++ b/test/DataTypesTestCases.rb @@ -1,57 +1,54 @@ -require 'bigdecimal' -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class DataTypesTestCases < FbTestCase - include FbTestCases - def gen_i(i) i end - + def gen_si(i) i end - + def gen_bi(i) i * 1000000000 end - + def gen_f(i) i / 2 end - + def gen_d(i) i * 3333 / 2 end - + def gen_c(i) "%c" % (i + 64) end - + def gen_c10(i) gen_c(i) * 5 end - + def gen_vc(i) gen_c(i) end - + def gen_vc10(i) gen_c(i) * i end - + def gen_vc10000(i) gen_c(i) * i * 1000 end - + def gen_dt(i) Date.civil(2000, i+1, i+1) end - + def gen_tm(i) Time.utc(1990, 1, 1, 12, i, i) end - + def gen_ts(i) Time.local(2006, 1, 1, i, i, i) end @@ -67,7 +64,7 @@ def gen_d92(i) def sum_i(range) range.inject(0) { |m, i| m + gen_i(i) } end - + def sum_si(range) range.inject(0) { |m, i| m + gen_si(i) } end @@ -75,19 +72,19 @@ def sum_si(range) def sum_bi(range) range.inject(0) { |m, i| m + gen_bi(i) } end - + def sum_f(range) range.inject(0) { |m, i| m + gen_f(i) } end - + def sum_d(range) range.inject(0) { |m, i| m + gen_d(i) } end - + def sum_n92(range) range.inject(0) { |m, i| m + gen_n92(i) } end - + def sum_d92(range) range.inject(0) { |m, i| m + gen_d92(i) } end @@ -98,7 +95,7 @@ def test_insert_basic_types I INTEGER, SI SMALLINT, BI BIGINT, - F FLOAT, + F FLOAT, D DOUBLE PRECISION, C CHAR, C10 CHAR(10), @@ -114,7 +111,7 @@ def test_insert_basic_types D185 DECIMAL(18,5)); END sql_insert = <<-END - insert into test + insert into test (I, SI, BI, F, D, C, C10, VC, VC10, VC10000, DT, TM, TS, N92, D92, N154, D185) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); @@ -129,10 +126,10 @@ def test_insert_basic_types connection.transaction do 10.times do |i| connection.execute( - sql_insert, + sql_insert, gen_i(i), gen_si(i), gen_bi(i), gen_f(i), gen_d(i), - gen_c(i), gen_c10(i), gen_vc(i), gen_vc10(i), gen_vc10000(i), + gen_c(i), gen_c10(i), gen_vc(i), gen_vc10(i), gen_vc10000(i), gen_dt(i), gen_tm(i), gen_ts(i), gen_n92(i), gen_d92(i), gen_n92(i), gen_d92(i)) end @@ -210,8 +207,7 @@ def test_insert_blobs_text sql_select = "select * from test order by id" Database.create(@parms) do |connection| connection.execute(sql_schema); - memo = IO.read("fb.c") - assert memo.size > 50000 + memo = "x" * 65535 connection.transaction do 10.times do |i| connection.execute(sql_insert, i, i.to_s, memo); @@ -234,14 +230,9 @@ def test_insert_blobs_binary sql_schema = "create table test (id int, name varchar(20), attachment blob segment size 1000)" sql_insert = "insert into test (id, name, attachment) values (?, ?, ?)" sql_select = "select * from test order by id" - #filename = "data.dat" - filename = "fb.c" Database.create(@parms) do |connection| connection.execute(sql_schema); - attachment = File.open(filename,"rb") do |f| - f.read * 3 - end - assert((attachment.size > 150000), "Not expected size") + attachment = SecureRandom.random_bytes(250_000) connection.transaction do 3.times do |i| connection.execute(sql_insert, i, i.to_s, attachment); @@ -367,7 +358,7 @@ def test_insert_incorrect_types assert_raises RangeError do connection.execute(sql_insert, 5000000000) end - elsif cols[i] == 'D92' + elsif cols[i] == 'D92' assert_raises TypeError do connection.execute(sql_insert, {:five => "five"}) end @@ -486,7 +477,7 @@ def test_insert_correct_types assert vals[0][0].is_a?(BigDecimal), "Numeric(9, 2) must return BigDecimal" assert_equal 12345.12, vals[0][0], "NUMERIC (decimal)" assert_equal 12345.12, vals[1][0], "NUMERIC (string)" - assert_equal -12345.12, vals[2][0], "NUMERIC (string)" + assert_equal(-12345.12, vals[2][0], "NUMERIC (string)") elsif cols[i] == 'D92' connection.execute(sql_insert, 12345.12) connection.execute(sql_insert, "12345.12") @@ -495,7 +486,7 @@ def test_insert_correct_types assert vals[0][0].is_a?(BigDecimal), "Decimal(9,2) must return BigDecimal" assert_equal 12345.12, vals[0][0], "DECIMAL (decimal)" assert_equal 12345.12, vals[1][0], "DECIMAL (string)" - assert_equal -12345.12, vals[2][0], "DECIMAL (string)" + assert_equal(-12345.12, vals[2][0], "DECIMAL (string)") elsif cols[i] == 'N154' connection.execute(sql_insert, 91520.65) connection.execute(sql_insert, "91520.65") @@ -518,29 +509,29 @@ def test_boolean_type sql_schema = "create table testboolean (id int generated by default as identity primary key, bval boolean)" sql_insert = "insert into testboolean (bval) values (?)" sql_select = "select * from testboolean order by id" - + Database.create(@parms) do |connection| - + connection.execute(sql_schema); - + connection.transaction do - + connection.execute(sql_insert, nil); connection.execute(sql_insert, false); connection.execute(sql_insert, true); - + 5.times do |i| connection.execute(sql_insert, i.even?); end - + end connection.execute(sql_select) do |cursor| i = 0 - + cursor.each :hash do |row| case i when 0 @@ -553,9 +544,9 @@ def test_boolean_type end i += 1 end - + end - + connection.drop end diff --git a/test/DatabaseTestCases.rb b/test/DatabaseTestCases.rb index 4f9aa69..fc7653b 100644 --- a/test/DatabaseTestCases.rb +++ b/test/DatabaseTestCases.rb @@ -1,30 +1,20 @@ -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class DatabaseTestCases < FbTestCase - include FbTestCases - def setup super - @database = "localhost:#{@db_file}" - @reader = { - :database => "localhost:#{@db_file}", - :username => 'rubytest', - :password => 'rubytest', - :charset => 'NONE', - :role => 'READER' } - @writer = { - :database => "localhost:#{@db_file}", - :username => 'rubytest', - :password => 'rubytest', - :charset => 'NONE', - :role => 'WRITER' } - end - + @parms = get_db_conn_params + @reader = @parms.merge(:username => 'rubytest', :password => 'rubytest', :role => 'READER') + @writer = @parms.merge(:username => 'rubytest', :password => 'rubytest', :role => 'WRITER') + @database = @reader[:database] + @db_file = @database.split(":", 2).last + end + def test_new db = Database.new assert_instance_of Database, db end - + def test_properties_read db = Database.new assert_nil db.database @@ -47,31 +37,33 @@ def test_properties_write db.role = 'READER' assert_equal 'READER', db.role end - + def test_initialize_hash db = Database.new(@parms) assert_equal @database, db.database - assert_equal @username, db.username - assert_equal @password, db.password + assert_equal @parms[:username], db.username + assert_equal @parms[:password], db.password assert_equal 'NONE', db.charset assert_equal 'READER', db.role end - + def test_initialize_string - db = Database.new(@parms_s) + params = @parms + params_s = get_db_conn_string(params) + db = Database.new params_s assert_equal @database, db.database - assert_equal @username, db.username - assert_equal @password, db.password + assert_equal params[:username], db.username + assert_equal params[:password], db.password assert_equal 'NONE', db.charset assert_equal 'READER', db.role end - + def test_create_instance db = Database.new(@parms) db.create - assert File.exists?(@db_file) + assert File.exist?(@db_file) end - + def test_create_instance_block db = Database.new(@parms) db.create do |connection| @@ -82,17 +74,17 @@ def test_create_instance_block assert_equal 3, connection.dialect assert_equal 3, connection.db_dialect end - assert File.exists?(@db_file) + assert File.exist?(@db_file) end - + def test_create_singleton - db = Database.create(@parms); - assert File.exists?(@db_file) + Database.create(@parms); + assert File.exist?(@db_file) end def test_create_singleton_with_defaults - db = Database.create(:database => "localhost:#{@db_file}"); - assert File.exists?(@db_file) + Database.create(:database => @parms[:database]); + assert File.exist?(@db_file) end def test_create_singleton_block @@ -103,18 +95,18 @@ def test_create_singleton_block end end assert_instance_of Database, db - assert File.exists?(@db_file) + assert File.exist?(@db_file) end - + def test_create_bad_param assert_raises TypeError do - db = Database.create(1) + Database.create(1) end end def test_create_bad_page_size assert_raises Error do - db = Database.create(@parms.merge(:page_size => 1000)) + Database.create(@parms.merge(:page_size => 1000)) end end @@ -126,37 +118,51 @@ def test_connect_instance end def test_connect_singleton - db = Database.create(@parms) + Database.create(@parms) connection = Database.connect(@parms) assert_instance_of Connection, connection connection.close end - + def test_drop_instance - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) db = Database.create(@parms) - assert File.exists?(@db_file) + assert File.exist?(@db_file) db.drop - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) end - + def test_drop_singleton - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) Database.create(@parms) - assert File.exists?(@db_file) + assert File.exist?(@db_file) Database.drop(@parms) - assert !File.exists?(@db_file) + assert !File.exist?(@db_file) end - + def test_role_support Database.create(@parms) do |connection| connection.execute("create table test (id int, test varchar(10))") connection.execute("create role writer") connection.execute("grant all on test to writer") - connection.execute("grant writer to rubytest") - connection.commit connection.execute("insert into test values (1, 'test role')") end + + connection = Database.connect(@parms) + begin + connection.execute("drop user rubytest") + connection.commit + rescue Error + ensure + connection.close rescue nil + end + + Database.connect(@parms) do |connection| + connection.execute("CREATE USER rubytest password 'rubytest'") + connection.execute("GRANT WRITER TO rubytest") + connection.commit + end + Database.connect(@reader) do |connection| assert_raises Error do connection.execute("select * from test") do |cursor| @@ -164,6 +170,7 @@ def test_role_support end end end + Database.connect(@writer) do |connection| connection.execute("select * from test") do |cursor| row = cursor.fetch :hash @@ -171,7 +178,6 @@ def test_role_support assert_equal 'test role', row["TEST"] end end - Database.drop(@parms) end end - + diff --git a/test/EncodingTestCases.rb b/test/EncodingTestCases.rb index 29ec9e9..f7cbaa5 100644 --- a/test/EncodingTestCases.rb +++ b/test/EncodingTestCases.rb @@ -1,39 +1,39 @@ #coding:utf-8 -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) -class EncodingTestCases < FbTestCase - include FbTestCases +if RUBY_VERSION =~ /^1.9/ + class EncodingTestCases < FbTestCase + def test_encoding + sql_schema = <<-END + create table TEST ( + ID INTEGER, + C10 CHAR(10), + VC10 VARCHAR(10), + MEMO BLOB SUB_TYPE TEXT) + END + sql_insert = <<-END + insert into test + (ID, C10, VC10, MEMO) + values + (?, ?, ?, ?); + END + sql_select = "select * from TEST order by ID" + lorem = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - def test_encoding - sql_schema = <<-END - create table TEST ( - ID INTEGER, - C10 CHAR(10), - VC10 VARCHAR(10), - MEMO BLOB SUB_TYPE TEXT) - END - sql_insert = <<-END - insert into test - (ID, C10, VC10, MEMO) - values - (?, ?, ?, ?); - END - sql_select = "select * from TEST order by ID" - lorem = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + params = @parms.merge(:encoding => "UTF-8") + Database.create(params) do |connection| + connection.execute(sql_schema) + connection.execute(sql_insert, 1, "abcdef", "한글", lorem) + row = connection.query(sql_select).first - Database.create(@parms.update(:encoding => "UTF-8")) do |connection| - connection.execute(sql_schema); - - connection.execute(sql_insert, 1, "abcdef", "한글", lorem) - - row = connection.query(sql_select).first - assert_equal 1, row[0] - assert_equal Encoding::UTF_8, row[1].encoding - assert_equal "abcdef ", row[1] - assert_equal Encoding::UTF_8, row[2].encoding - assert_equal "한글", row[2] - assert_equal Encoding::UTF_8, row[3].encoding - assert_equal lorem, row[3] + assert_equal 1, row[0] + assert_equal Encoding::UTF_8, row[1].encoding + assert_equal "abcdef ", row[1] + assert_equal Encoding::UTF_8, row[2].encoding + assert_equal "한글", row[2] + assert_equal Encoding::UTF_8, row[3].encoding + assert_equal lorem, row[3] + end end end -end +end \ No newline at end of file diff --git a/test/FbTestCases.rb b/test/FbTestCases.rb deleted file mode 100644 index c5f9f8a..0000000 --- a/test/FbTestCases.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'fileutils' -include FileUtils -require 'fb' - -if RUBY_VERSION =~ /^2/ - require 'minitest/autorun' - - unless Minitest.const_defined?('Test') - Minitest::Test = MiniTest::Unit::TestCase - end - - class FbTestCase < Minitest::Test - end - -else - require 'test/unit' - - class FbTestCase < Test::Unit::TestCase - def default_test - end - end -end - -module FbTestCases - include Fb - - def setup - @db_file = case RUBY_PLATFORM - when /win32/ then 'c:/var/fbdata/drivertest.fdb' - when /darwin/ then File.join(File.expand_path(File.dirname(__FILE__)), 'drivertest.fdb') - else '/var/fbdata/drivertest.fdb' - end - @db_host = 'localhost' - @username = 'sysdba' - @password = 'masterkey' - @parms = { - :database => "#{@db_host}:#{@db_file}", - :username => @username, - :password => @password, - :charset => 'NONE', - :role => 'READER' } - @parms_s = "database = #{@db_host}:#{@db_file}; username = #{@username}; password = #{@password}; charset = NONE; role = READER;" - @fb_version = -1 - rm_rf @db_file - - Database.create(@parms) do |connection| - - d = connection.query("SELECT substring(rdb$get_context('SYSTEM', 'ENGINE_VERSION') from 1 for 1) from rdb$database") - - @fb_version = Integer(d.first[0]) - - connection.drop - end - - rm_rf @db_file - end - -end - -class Fb::Connection - def execute_script(sql_schema) - self.transaction do - sql_schema.strip.split(';').each do |stmt| - self.execute(stmt); - end - end - end -end diff --git a/test/FbTestSuite.rb b/test/FbTestSuite.rb deleted file mode 100644 index 5a9cefb..0000000 --- a/test/FbTestSuite.rb +++ /dev/null @@ -1,12 +0,0 @@ -$: << File.dirname(__FILE__) -$: << File.join(File.dirname(__FILE__),'..') - -require 'DatabaseTestCases' -require 'ConnectionTestCases' -require 'CursorTestCases' -require 'DataTypesTestCases' -require 'NumericDataTypesTestCases' -require 'TransactionTestCases' -if RUBY_VERSION =~ /^1.9/ - require 'EncodingTestCases' -end diff --git a/test/NumericDataTypesTestCases.rb b/test/NumericDataTypesTestCases.rb index 9dd6f6b..e23a3e5 100644 --- a/test/NumericDataTypesTestCases.rb +++ b/test/NumericDataTypesTestCases.rb @@ -1,9 +1,6 @@ -require 'bigdecimal' -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class NumericDataTypesTestCases < FbTestCase - include FbTestCases - def setup super @connection = Database.create(@parms).connect @@ -39,10 +36,10 @@ def test_smallint_max def test_smallint_min prepare_test_table("smallint") - assert_equal -32768, write_and_read_value(-32768) - assert_equal -32768, write_and_read_value("-32768") - assert_equal -32768, write_and_read_value(-32768.0) - assert_equal -32768, write_and_read_value(BigDecimal("-32768")) + assert_equal(-32768, write_and_read_value(-32768)) + assert_equal(-32768, write_and_read_value("-32768")) + assert_equal(-32768, write_and_read_value(-32768.0)) + assert_equal(-32768, write_and_read_value(BigDecimal("-32768"))) assert write_and_read_value(-32768).is_a?(Fixnum) assert write_and_read_value("-32768").is_a?(Fixnum) assert write_and_read_value(-32768.0).is_a?(Fixnum) @@ -60,9 +57,9 @@ def test_smallint_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_smallint_input_type @@ -97,10 +94,10 @@ def test_integer_max def test_integer_min prepare_test_table("integer") - assert_equal -2147483648, write_and_read_value(-2147483648) - assert_equal -2147483648, write_and_read_value("-2147483648") - assert_equal -2147483648, write_and_read_value(-2147483648.0) - assert_equal -2147483648, write_and_read_value(BigDecimal("-2147483648")) + assert_equal(-2147483648, write_and_read_value(-2147483648)) + assert_equal(-2147483648, write_and_read_value("-2147483648")) + assert_equal(-2147483648, write_and_read_value(-2147483648.0)) + assert_equal(-2147483648, write_and_read_value(BigDecimal("-2147483648"))) assert write_and_read_value(-2147483648).is_a?(Fixnum) assert write_and_read_value("-2147483648").is_a?(Fixnum) assert write_and_read_value(-2147483648.0).is_a?(Fixnum) @@ -118,9 +115,9 @@ def test_integer_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_integer_input_type @@ -155,10 +152,10 @@ def test_bigint_max def test_bigint_min prepare_test_table("bigint") - assert_equal -9223372036854775808, write_and_read_value(-9223372036854775808) - assert_equal -9223372036854775808, write_and_read_value("-9223372036854775808") + assert_equal(-9223372036854775808, write_and_read_value(-9223372036854775808)) + assert_equal(-9223372036854775808, write_and_read_value("-9223372036854775808")) #assert_equal -9223372036854775808, write_and_read_value(-9223372036854775808.0) - assert_equal -9223372036854775808, write_and_read_value(BigDecimal("-9223372036854775808")) + assert_equal(-9223372036854775808, write_and_read_value(BigDecimal("-9223372036854775808"))) assert write_and_read_value(-9223372036854775808).is_a?(Bignum) assert write_and_read_value("-9223372036854775808").is_a?(Bignum) #assert write_and_read_value(-9223372036854775808.0).is_a?(Bignum) @@ -176,9 +173,9 @@ def test_bigint_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_bigint_input_type @@ -213,10 +210,10 @@ def test_decimal_4_0_max def test_decimal_4_0_min prepare_test_table("decimal(4, 0)") - assert_equal -32768, write_and_read_value(-32768) - assert_equal -32768, write_and_read_value("-32768") - assert_equal -32768, write_and_read_value(-32768.0) - assert_equal -32768, write_and_read_value(BigDecimal("-32768")) + assert_equal(-32768, write_and_read_value(-32768)) + assert_equal(-32768, write_and_read_value("-32768")) + assert_equal(-32768, write_and_read_value(-32768.0)) + assert_equal(-32768, write_and_read_value(BigDecimal("-32768"))) assert write_and_read_value(-32768).is_a?(Fixnum) assert write_and_read_value("-32768").is_a?(Fixnum) assert write_and_read_value(-32768.0).is_a?(Fixnum) @@ -234,9 +231,9 @@ def test_decimal_4_0_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_decimal_4_0_input_type @@ -292,9 +289,9 @@ def test_decimal_9_0_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_decimal_9_0_input_type @@ -437,10 +434,10 @@ def test_decimal_18_0_max def test_decimal_18_0_min prepare_test_table("decimal(18, 0)") - assert_equal -9223372036854775808, write_and_read_value(-9223372036854775808) - assert_equal -9223372036854775808, write_and_read_value("-9223372036854775808") + assert_equal(-9223372036854775808, write_and_read_value(-9223372036854775808)) + assert_equal(-9223372036854775808, write_and_read_value("-9223372036854775808")) #assert_equal -9223372036854775808, write_and_read_value(-9223372036854775808.0) - assert_equal -9223372036854775808, write_and_read_value(BigDecimal("-9223372036854775808")) + assert_equal(-9223372036854775808, write_and_read_value(BigDecimal("-9223372036854775808"))) assert write_and_read_value(-9223372036854775808).is_a?(Bignum) assert write_and_read_value("-9223372036854775808").is_a?(Bignum) #assert write_and_read_value(-9223372036854775808.0).is_a?(Bignum) @@ -458,9 +455,9 @@ def test_decimal_18_0_rounding assert_equal 1, write_and_read_value(0.5) assert_equal 1, write_and_read_value("0.5") assert_equal 1, write_and_read_value(BigDecimal.new("0.5")) - assert_equal -1, write_and_read_value(-0.5) - assert_equal -1, write_and_read_value("-0.5") - assert_equal -1, write_and_read_value(BigDecimal.new("-0.5")) + assert_equal(-1, write_and_read_value(-0.5)) + assert_equal(-1, write_and_read_value("-0.5")) + assert_equal(-1, write_and_read_value(BigDecimal.new("-0.5"))) end def test_decimal_18_0_input_types diff --git a/test/TransactionTestCases.rb b/test/TransactionTestCases.rb index 1f05d13..937b9f0 100644 --- a/test/TransactionTestCases.rb +++ b/test/TransactionTestCases.rb @@ -1,11 +1,8 @@ -require 'test/FbTestCases' +require File.expand_path("../test_helper", __FILE__) class TransactionTestCases < FbTestCase - include FbTestCases - def test_transaction Database.create(@parms) do |connection| - n = 0 assert !connection.transaction_started connection.transaction assert connection.transaction_started @@ -21,7 +18,6 @@ def test_transaction def test_transaction_block Database.create(@parms) do |connection| - n = 0 assert !connection.transaction_started connection.transaction do assert connection.transaction_started @@ -72,7 +68,7 @@ def test_auto_transaction_insert_with_exception def test_auto_transaction_query Database.create(@parms) do |connection| assert !connection.transaction_started - rs = connection.query("select * from rdb$database") + connection.query("select * from rdb$database") assert !connection.transaction_started connection.drop end @@ -83,7 +79,7 @@ def test_query_in_transaction assert !connection.transaction_started connection.transaction do assert connection.transaction_started - rs = connection.query("select * from rdb$database") + connection.query("select * from rdb$database") assert connection.transaction_started end assert !connection.transaction_started @@ -179,8 +175,8 @@ def test_transaction_block_insert_rollback def test_simultaneous_transactions db_file1 = "#{@db_file}1" db_file2 = "#{@db_file}2" - rm_rf db_file1 - rm_rf db_file2 + FileUtils.rm_rf db_file1 + FileUtils.rm_rf db_file2 parms1 = @parms.merge(:database => "#{@db_host}:#{db_file1}") parms2 = @parms.merge(:database => "#{@db_host}:#{db_file2}") Database.create(parms1) do |conn1| @@ -262,7 +258,7 @@ def test_auto_and_explicit_transactions Database.create(@parms) do |conn| conn.execute(sql_schema) conn.transaction { 10.times { |i| conn.execute(sql_insert, i, "NAME#{i}") } } - result = conn.query(sql_select) + conn.query(sql_select) assert !conn.transaction_started conn.transaction("READ COMMITTED") do assert conn.transaction_started diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..c1d1014 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,91 @@ +require 'rubygems' +require 'tmpdir' +require 'fileutils' +require 'securerandom' +require 'bigdecimal' +require 'fb' + +if RUBY_VERSION =~ /^2/ + require 'minitest/autorun' + + unless Minitest.const_defined?('Test') + Minitest::Test = MiniTest::Unit::TestCase + end + + class FbTestCase < Minitest::Test + end + +else + require 'test/unit' + + class FbTestCase < Test::Unit::TestCase + def default_test + end + end +end + +class FbTestCase + include Fb + + def setup + @parms = get_db_conn_params("drivertest.fdb") + @parms_s = get_db_conn_string(@parms) + @db_file = @parms[:database].split(":", 2).last + @db_host = "localhost" + @fb_version = get_fb_version + end + + def teardown + Database.drop(@parms) rescue nil + end + + def get_db_conn_params(dbname = nil) + dbname ||= "drivertest.%s.fdb" % SecureRandom.hex(24) + + db_file = case RUBY_PLATFORM + when /win32/ + File.join("c:", "var", "fbdata", dbname) + else + File.join("/", "tmp", "firebird", dbname) + end + { + :database => "localhost:#{db_file}", + :username => "sysdba", + :password => "masterkey", + :charset => 'NONE', + :role => 'READER' + } + end + + def get_db_conn_string(params = nil) + params ||= get_db_conn_params + "database = #{params[:database]}; username = #{params[:username]}; password = #{params[:password]}; charset = NONE; role = READER;" + end + + def get_fb_version + @@fb_version ||= begin + version = -1 + params = get_db_conn_params("fbversion.fdb") + begin + Database.create(params) do |connection| + d = connection.query("SELECT substring(rdb$get_context('SYSTEM', 'ENGINE_VERSION') from 1 for 1) from rdb$database") + version = Integer(d.first[0]) + connection.drop + end + ensure + Database.drop(params) rescue nil + end + version + end + end +end + +class Fb::Connection + def execute_script(sql_schema) + self.transaction do + sql_schema.strip.split(';').each do |stmt| + self.execute(stmt) + end + end + end +end \ No newline at end of file