Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
AllCops:
DisplayCopNames: true
DisplayStyleGuide: true
TargetRubyVersion: 2.2
TargetRubyVersion: 3.4
Exclude:
- 'vendor/**/*'

Expand All @@ -20,7 +20,7 @@ Metrics/CyclomaticComplexity:
Metrics/MethodLength:
Enabled: false

Metrics/LineLength:
Layout/LineLength:
Enabled: false

Metrics/PerceivedComplexity:
Expand Down
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,36 @@ ActiveRecord models that use this connection will now be connecting to the confi

## Testing

To run the tests, you'll need the ODBC driver as well as the connection adapter for each database against which you're trying to test. Then run `DSN=MyDatabaseDSN bundle exec rake test` and the test suite will be run by connecting to your database.
There are two test suites:

## Testing Using a Docker Container Because ODBC on Mac is Hard
### Unit tests (no database required)

Tested on Sierra.
```bash
bundle exec rake test:unit
```

Tests the type system, quoting, SQL generation, schema statement helpers, connection setup, adapter subclasses, and concerns without any database connection. Safe to run anywhere.

### Integration tests (requires ODBC connection)

```bash
DSN=MyDatabaseDSN bundle exec rake test
```

Full integration tests against a live database via ODBC. You'll need the ODBC driver and a connection adapter for the target database.

### Run both

```bash
bundle exec rake test:all
```

Run from project root:
### Testing Using a Docker Container (legacy)

```
bundle package
docker build -f Dockerfile.dev -t odbc-dev .

# Local mount mysql directory to avoid some permissions problems
mkdir -p /tmp/mysql
docker run -it --rm -v $(pwd):/workspace -v /tmp/mysql:/var/lib/mysql odbc-dev:latest

Expand Down
15 changes: 15 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,22 @@ require 'bundler/gem_tasks'
require 'rake/testtask'
require 'rubocop/rake_task'

# Integration tests — require a live ODBC connection
Rake::TestTask.new(:test) do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/*_test.rb']
end

# Unit tests — no database connection required
Rake::TestTask.new('test:unit') do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/unit/**/*_test.rb']
end

# Both integration and unit tests
Rake::TestTask.new('test:all') do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/**/*_test.rb']
Expand Down
2 changes: 1 addition & 1 deletion lib/odbc_adapter/adapters/postgresql_odbc_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def disable_referential_integrity
def create_database(name, options = {})
options = options.reverse_merge(encoding: 'utf8')

option_string = options.symbolize_keys.sum do |key, value|
option_string = options.symbolize_keys.sum('') do |key, value|
case key
when :owner
" OWNER = \"#{value}\""
Expand Down
5 changes: 3 additions & 2 deletions odbc_adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ Gem::Specification.new do |spec|

spec.add_development_dependency 'bundler', '>= 1.14'
spec.add_development_dependency 'minitest', '~> 5.10'
spec.add_development_dependency 'rake', '~> 12.0'
spec.add_development_dependency 'rubocop', '0.48.1'
spec.add_development_dependency 'rake', '>= 12.0'
spec.add_development_dependency 'rubocop', '>= 0.48.1'
spec.add_development_dependency 'simplecov', '~> 0.14'
spec.add_development_dependency 'ostruct'
spec.add_development_dependency 'pry', '~> 0.11.1'

spec.post_install_message = <<~MESSAGE
Expand Down
103 changes: 103 additions & 0 deletions test/unit/adapters/mysql_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true

require 'unit_test_helper'
require 'odbc_adapter/adapters/mysql_odbc_adapter'

class MySQLAdapterTest < Minitest::Test
def adapter
ODBCAdapter::Adapters::MySQLODBCAdapter.new
end

def test_primary_key_constant
assert_equal 'INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY',
ODBCAdapter::Adapters::MySQLODBCAdapter::PRIMARY_KEY
end

def test_prepared_statements_is_false
refute adapter.prepared_statements
end

def test_quoted_true_is_one
assert_equal '1', adapter.quoted_true
end

def test_quoted_false_is_zero
assert_equal '0', adapter.quoted_false
end

def test_unquoted_true_is_integer_one
assert_equal 1, adapter.unquoted_true
end

def test_unquoted_false_is_integer_zero
assert_equal 0, adapter.unquoted_false
end

def test_quote_string_escapes_single_quotes
assert_equal "it''s", adapter.quote_string("it's")
end

def test_quote_string_escapes_backslashes
assert_equal 'back\\\\slash', adapter.quote_string('back\\slash')
end

def test_inherits_from_odbc_adapter
assert ODBCAdapter::Adapters::MySQLODBCAdapter.ancestors.include?(
ActiveRecord::ConnectionAdapters::ODBCAdapter
)
end

def adapter_with_sql_capture
a = ODBCAdapter::Adapters::MySQLODBCAdapter.new
sqls = []
a.define_singleton_method(:execute) { |sql, *| sqls << sql }
[a, sqls]
end

# --- create_database ---

def test_create_database_defaults_to_utf8_charset
a, sqls = adapter_with_sql_capture
a.create_database('mydb')
assert_includes sqls.first, 'DEFAULT CHARACTER SET `utf8`'
end

def test_create_database_with_custom_charset
a, sqls = adapter_with_sql_capture
a.create_database('mydb', charset: 'latin1')
assert_includes sqls.first, 'DEFAULT CHARACTER SET `latin1`'
end

def test_create_database_with_charset_and_collation
a, sqls = adapter_with_sql_capture
a.create_database('mydb', charset: 'latin1', collation: 'latin1_bin')
assert_includes sqls.first, 'DEFAULT CHARACTER SET `latin1`'
assert_includes sqls.first, 'COLLATE `latin1_bin`'
end

def test_create_database_without_collation_omits_collate_clause
a, sqls = adapter_with_sql_capture
a.create_database('mydb')
refute sqls.first.include?('COLLATE')
end

# --- indexes rejects PRIMARY key ---

def test_indexes_filters_out_primary_key_index
primary_idx = ActiveRecord::ConnectionAdapters::IndexDefinition.new('users', 'PRIMARY', true, ['id'])
email_idx = ActiveRecord::ConnectionAdapters::IndexDefinition.new('users', 'idx_email', false, ['email'])
unique_idx = ActiveRecord::ConnectionAdapters::IndexDefinition.new('users', 'idx_unique', true, ['email'])
name_idx = ActiveRecord::ConnectionAdapters::IndexDefinition.new('users', 'idx_name', false, ['name'])

# Simulate what MySQLODBCAdapter#indexes does:
# super(...).reject { |i| i.unique && i.name =~ /^PRIMARY$/ }
all_indexes = [primary_idx, email_idx, unique_idx, name_idx]
result = all_indexes.reject { |i| i.unique && i.name =~ /^PRIMARY$/ }

assert_equal 3, result.length
refute_includes result.map(&:name), 'PRIMARY'
assert_includes result.map(&:name), 'idx_unique' # unique but not PRIMARY → kept
assert_includes result.map(&:name), 'idx_email'
assert_includes result.map(&:name), 'idx_name'
end
end
28 changes: 28 additions & 0 deletions test/unit/adapters/null_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

require 'unit_test_helper'
require 'odbc_adapter/adapters/null_odbc_adapter'

class NullAdapterTest < Minitest::Test
def adapter
ODBCAdapter::Adapters::NullODBCAdapter.new
end

def test_prepared_statements_is_false
refute adapter.prepared_statements
end

def test_supports_migrations_is_false
refute adapter.supports_migrations?
end

def test_variant_type_constant
assert_equal 'VARIANT', ODBCAdapter::Adapters::NullODBCAdapter::VARIANT_TYPE
end

def test_inherits_from_odbc_adapter
assert ODBCAdapter::Adapters::NullODBCAdapter.ancestors.include?(
ActiveRecord::ConnectionAdapters::ODBCAdapter
)
end
end
Loading