cwninja-active_record_lint 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,23 @@
1
+ ActiveRecord::Lint
2
+ ================
3
+
4
+ A library to support the automatic checking for the doing of stupid things
5
+ with ActiveRecord.
6
+
7
+ AR::Lint is not big, nor is it clever, nor is it that well written.
8
+ It makes recommendations based upon what I have found to be good practice, with
9
+ only anecdotal evidence to support it.
10
+
11
+ This is *not* a substitute for a DB admin, nor is it a substitute for knoledge.
12
+
13
+ Your mileage may vary, remember to check your tire pressure.
14
+
15
+ Usage
16
+ -----
17
+
18
+ You can check a typical rails application by executing:
19
+ > $ arlint path/to/rails/app
20
+
21
+ Support for automated tests and making it work with rake is something I could do to get around to.
22
+
23
+ Copyright (c) 2008 Tom Lea, released under the MIT Licence
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+ require 'date'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ namespace :test do
12
+ desc 'Functional tests.'
13
+ Rake::TestTask.new(:functional) do |t|
14
+ t.libs << 'lib'
15
+ t.pattern = 'test/functional/*_test.rb'
16
+ t.verbose = true
17
+ end
18
+ desc 'Unit tests.'
19
+ Rake::TestTask.new(:unit) do |t|
20
+ t.libs << 'lib'
21
+ t.pattern = 'test/unit/*_test.rb'
22
+ t.verbose = true
23
+ end
24
+ end
25
+
26
+ task :test => ["test:functional", "test:unit"]
27
+
28
+ spec = Gem::Specification.new do |s|
29
+ s.name = %q{active_record_lint}
30
+ s.version = "0.0.3"
31
+ s.summary = %q{Rails tool to find foreign keys without indexes and other common issues.}
32
+ s.description = %q{A library to support the automatic checking for the doing of stupid things with ActiveRecord.}
33
+
34
+ s.executables = ["arlint"]
35
+ s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'test/**/*.rb']
36
+ s.require_path = 'lib'
37
+ s.test_files = Dir[*['test/**/*_test.rb']]
38
+ s.homepage = "http://github.com/cwninja/active_record_lint"
39
+
40
+ s.has_rdoc = true
41
+ s.extra_rdoc_files = ["README.markdown"]
42
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.markdown"]
43
+
44
+ s.authors = ["Tom Lea"]
45
+ s.email = %q{commits@tomlea.co.uk}
46
+
47
+ s.platform = Gem::Platform::RUBY
48
+ end
49
+
50
+ Rake::GemPackageTask.new spec do |pkg|
51
+ pkg.need_tar = true
52
+ pkg.need_zip = true
53
+ end
54
+
55
+ desc "Clean files generated by rake tasks"
56
+ task :clobber => [:clobber_rdoc, :clobber_package]
57
+
58
+ desc "Generate a gemspec file"
59
+ task :gemspec do
60
+ File.open("#{spec.name}.gemspec", 'w') do |f|
61
+ f.write spec.to_ruby
62
+ end
63
+ end
64
+
data/bin/arlint ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ path = ARGV.last || Dir.pwd
4
+
5
+ boot_path = File.join(path, 'config', 'boot.rb')
6
+ environment_path = File.join(path, 'config', 'environment.rb')
7
+
8
+ unless(File.exists?(boot_path) and File.exists?(environment_path))
9
+ puts "Usage: #{$0} path/to/rails/root"
10
+ exit(1)
11
+ end
12
+
13
+ require boot_path
14
+ require environment_path
15
+ require 'active_record_lint'
16
+
17
+ ActiveRecord::Lint.load_models(path)
18
+
19
+ scanner = ActiveRecord::Lint::Scanner.new()
20
+ reporter = ActiveRecord::Lint::Reporter.new(scanner)
21
+
22
+ puts reporter
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+
4
+ module ActiveRecord::Lint
5
+ def load_models(rails_root)
6
+ pattern = File.join(rails_root, "app", "models", "*.rb")
7
+ Dir.glob(pattern){|file|
8
+ load( file )
9
+ }
10
+ end
11
+
12
+ def unload_models
13
+ models = ActiveRecord::Base.send :class_variable_get, :@@subclasses
14
+ models = models.keys - [ActiveRecord::Base]
15
+ models.map(&:name).each do |name|
16
+ Object.send :remove_const, name unless name.nil? or name.empty?
17
+ end
18
+ ActiveRecord::Base.send :class_variable_set, :@@subclasses, {}
19
+ end
20
+
21
+ def missing_indexes(options = {})
22
+ load_models(options[:rails_root] || RAILS_ROOT)
23
+ Scanner.new(options[:connection] || ActiveRecord::Base.connection).missing_indexes
24
+ end
25
+
26
+ extend self
27
+ end
28
+
29
+
30
+ Dir.glob(File.join(File.dirname(__FILE__), "lint", "*.rb")) do |file|
31
+ require file
32
+ end
@@ -0,0 +1,28 @@
1
+ unless defined? Memoize
2
+ module Memoize
3
+
4
+ def self.included(other)
5
+ other.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def memoize(*methods)
10
+ methods.each do |method|
11
+ define_method "#{method}_with_memoize" do |*args|
12
+ memoize_store_for(method)[args] ||= send("#{method}_without_memoize", *args)
13
+ end
14
+
15
+ alias_method_chain method, :memoize
16
+ end
17
+ end
18
+ end
19
+
20
+ def memoize_store_for(method)
21
+ unless store = instance_variable_get("@_#{method}_memoized")
22
+ instance_variable_set("@_#{method}_memoized", store = {})
23
+ end
24
+ store
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,53 @@
1
+ module ActiveRecord::Lint
2
+ class Pair
3
+ include Comparable
4
+ attr_accessor :a, :b
5
+
6
+ def initialize(a, b)
7
+ @a,@b=a,b
8
+ end
9
+
10
+ def <=>(other)
11
+ (a <=> other.a).zero? ? (b <=> other.b) : (a <=> other.a)
12
+ end
13
+
14
+ def eql?(other)
15
+ (self <=> other) == 0
16
+ end
17
+
18
+ def pair_name
19
+ @pair_name ||= self.class.name.split("::").last
20
+ end
21
+
22
+ def inspect
23
+ "#{pair_name}[#{a.inspect}, #{b.inspect}]"
24
+ end
25
+
26
+ def hash
27
+ a.hash ^ b.hash
28
+ end
29
+
30
+ def to_ary
31
+ [a,b]
32
+ end
33
+
34
+ alias to_a to_ary
35
+
36
+ class << self
37
+ alias [] new
38
+ end
39
+ end
40
+
41
+ class TableColumnPair < Pair
42
+ alias table a
43
+ alias column b
44
+ end
45
+
46
+ class TableKeyPair < TableColumnPair
47
+ alias key b
48
+ end
49
+
50
+ class TableIndexPair < TableColumnPair
51
+ alias index b
52
+ end
53
+ end
@@ -0,0 +1,89 @@
1
+ require File.join(File.dirname(__FILE__), "pairs")
2
+
3
+ module ActiveRecord::Lint
4
+ class MissingIndex < TableIndexPair
5
+ def to_s
6
+ "The foreign key '#{index}' is not indexed on '#{table}'."
7
+ end
8
+ end
9
+
10
+ class MissingTable
11
+ include Comparable
12
+ attr_reader :table
13
+
14
+ def initialize(table)
15
+ @table=table
16
+ end
17
+
18
+ def <=> (other)
19
+ table <=> other.table
20
+ end
21
+
22
+ def to_s
23
+ "Expected the table '#{table}' to exist."
24
+ end
25
+ end
26
+
27
+ class MissingForeignKey < TableKeyPair
28
+ def to_s
29
+ "Missing foreign key '#{key}' on '#{table}'."
30
+ end
31
+ end
32
+
33
+
34
+ class Reporter
35
+ include Memoize
36
+ SUMMARY_NAMES = ["missing_indexes", "missing_tables", "missing_foreign_keys"]
37
+
38
+ def initialize(scanner)
39
+ @scanner = scanner
40
+ end
41
+
42
+ def missing_indexes
43
+ @scanner.missing_indexes.map{|pair| MissingIndex[*pair.to_ary] }
44
+ end
45
+ memoize :missing_indexes
46
+
47
+ def missing_tables
48
+ tables = @scanner.missing_tables.map{|table_issue| MissingTable.new(table_issue) }
49
+ if defined?(ActionController::Base) and ActionController::Base.session_store != :active_record_store
50
+ tables.reject!{|table| table.table}
51
+ end
52
+ tables
53
+ end
54
+ memoize :missing_tables
55
+
56
+ def missing_foreign_keys
57
+ @scanner.missing_foreign_keys.map{|pair| MissingForeignKey[*pair.to_ary] }
58
+ end
59
+ memoize :missing_foreign_keys
60
+
61
+ def issues
62
+ SUMMARY_NAMES.map{|name| send(name) }.sum
63
+ end
64
+
65
+
66
+ def to_s
67
+ lines = returning([]){|output|
68
+ SUMMARY_NAMES.each do |name|
69
+ issues = send(name)
70
+ unless issues.empty?
71
+ output << "== #{name} =="
72
+ issues.each do |issue|
73
+ output << "* #{issue}"
74
+ end
75
+ end
76
+ end
77
+ }
78
+ if lines.empty?
79
+ "No issues found"
80
+ else
81
+ lines.join("\n")
82
+ end
83
+ end
84
+
85
+ private
86
+ attr_writer *SUMMARY_NAMES
87
+ end
88
+ end
89
+
@@ -0,0 +1,61 @@
1
+ class ActiveRecord::Lint::Scanner
2
+ include ActiveRecord::Lint
3
+ include Memoize
4
+
5
+ def initialize(connection = nil)
6
+ @connection = connection || ActiveRecord::Base.connection
7
+ end
8
+
9
+ def missing_indexes
10
+ foreign_keys - indexes
11
+ end
12
+
13
+ def missing_tables
14
+ classes.map{|klass| klass.table_name } - @connection.tables
15
+ end
16
+
17
+ def missing_foreign_keys
18
+ foreign_keys - columns
19
+ end
20
+
21
+ def foreign_keys
22
+ returning [] do |foreign_keys|
23
+ classes.each do |klass|
24
+ table_name = klass.table_name
25
+ klass.reflect_on_all_associations(:belongs_to).map(&:primary_key_name).each do |foreign_key|
26
+ foreign_keys << TableColumnPair.new(table_name, foreign_key)
27
+ end
28
+ end
29
+ end.uniq
30
+ end
31
+ memoize :foreign_keys
32
+
33
+ def columns
34
+ returning [] do |columns|
35
+ @connection.tables.each do |table|
36
+ @connection.columns(table).each do |column|
37
+ columns << TableColumnPair.new(table, column.name)
38
+ end
39
+ end
40
+ end.uniq
41
+ end
42
+ memoize :columns
43
+
44
+ def indexes
45
+ returning [] do |indexes|
46
+ @connection.tables.each do |table|
47
+ column_sets = @connection.indexes(table).map(&:columns)
48
+ column_sets.select{|col| col.size == 1}.flatten.each do |index|
49
+ indexes << TableIndexPair.new(table, index)
50
+ end
51
+ end
52
+ end.uniq
53
+ end
54
+ memoize :indexes
55
+
56
+ def classes
57
+ ActiveRecord::Base.send(:subclasses)
58
+ end
59
+ memoize :classes
60
+
61
+ end
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "active_record", "lint")
@@ -0,0 +1,5 @@
1
+ class Crime < ActiveRecord::Base
2
+ has_many :incidents
3
+ has_many :victims, :through => :incidents
4
+ has_many :criminals, :through => :incidents
5
+ end
@@ -0,0 +1,5 @@
1
+ class Criminal < ActiveRecord::Base
2
+ has_many :incidents
3
+ has_many :victims, :through => :incidents
4
+ has_many :crimes, :through => :incidents
5
+ end
@@ -0,0 +1,5 @@
1
+ class Incident < ActiveRecord::Base
2
+ belongs_to :criminal
3
+ belongs_to :victim
4
+ belongs_to :crime
5
+ end
@@ -0,0 +1,3 @@
1
+ class Victim < ActiveRecord::Base
2
+ has_many :incidents
3
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class MissingForeignKeysFunctionalTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ include ActiveRecord::Lint
6
+
7
+ def setup
8
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
9
+ ActiveRecord::Lint::load_models(@rails_root)
10
+ super
11
+ @connection.remove_column :incidents, :criminal_id
12
+ end
13
+
14
+ def test_should_not_error_because_we_are_missing_criminal_id
15
+ missing_indexes = ActiveRecord::Lint::Scanner.new(@connection).missing_indexes
16
+
17
+ assert_array_equal [Pair["incidents", "criminal_id"], Pair["incidents", "crime_id"]], missing_indexes
18
+ end
19
+
20
+ def test_should_report_lack_of_criminal_id_on_incidents_table
21
+ missing_foreign_keys = ActiveRecord::Lint::Scanner.new(@connection).missing_foreign_keys
22
+
23
+ assert_array_equal [Pair["incidents", "criminal_id"]], missing_foreign_keys
24
+ end
25
+
26
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class MissingIndexesAssociationsFunctionalTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ Pair = ActiveRecord::Lint::Pair
6
+ def setup
7
+ ActiveRecord::Lint::unload_models
8
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
9
+ super
10
+ end
11
+
12
+ def test_should_know_we_need_an_index_on_victims
13
+ ActiveRecord::Lint::load_models(@rails_root)
14
+
15
+ missing_indexes = ActiveRecord::Lint::Scanner.new(@connection).missing_indexes
16
+
17
+ assert_array_equal [Pair["incidents", "criminal_id"], Pair["incidents", "crime_id"]], missing_indexes
18
+ end
19
+
20
+ def test_should_be_able_to_call_missing_indexes_on_module
21
+ missing_indexes = ActiveRecord::Lint.missing_indexes(:rails_root => @rails_root)
22
+
23
+ assert_array_equal [Pair["incidents", "criminal_id"], Pair["incidents", "crime_id"]], missing_indexes
24
+ end
25
+
26
+ def test_should_handle_inherited_models
27
+ ActiveRecord::Lint::load_models(@rails_root)
28
+
29
+ my_model = Class.new(Incident)
30
+ missing_indexes = ActiveRecord::Lint::Scanner.new(@connection).missing_indexes
31
+
32
+ assert_array_equal [Pair["incidents", "criminal_id"], Pair["incidents", "crime_id"]], missing_indexes
33
+ end
34
+
35
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class MissingTablesFunctionalTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ Pair = ActiveRecord::Lint::Pair
6
+
7
+ def setup
8
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
9
+ ActiveRecord::Lint::load_models(@rails_root)
10
+ super
11
+ @connection.drop_table :criminals
12
+ end
13
+
14
+ def test_should_not_error_because_we_have_no_criminals_table
15
+ missing_indexes = ActiveRecord::Lint::Scanner.new(@connection).missing_indexes
16
+
17
+ assert_array_equal [Pair["incidents", "criminal_id"], Pair["incidents", "crime_id"]], missing_indexes
18
+ end
19
+
20
+ def test_should_report_lack_of_criminals_table
21
+ missing_tables = ActiveRecord::Lint::Scanner.new(@connection).missing_tables
22
+
23
+ assert_array_equal ["criminals"], missing_tables
24
+ end
25
+
26
+ end
@@ -0,0 +1,85 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class ReporterMissingIndexesFunctionalTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ Lint = ActiveRecord::Lint
6
+ Pair = Lint::Pair
7
+
8
+ def setup
9
+ super
10
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
11
+ Lint::load_models(@rails_root)
12
+ end
13
+
14
+ def test_should_report_missing_indexes_on_incidents
15
+ scanner = Lint::Scanner.new(@connection)
16
+ reporter = Lint::Reporter.new(scanner)
17
+
18
+ assert_array_includes Lint::MissingIndex["incidents", "crime_id"], Lint::MissingIndex["incidents", "criminal_id"], reporter.missing_indexes
19
+ end
20
+
21
+ def test_issues_should_report_missing_indexes_on_incidents
22
+ scanner = Lint::Scanner.new(@connection)
23
+ reporter = Lint::Reporter.new(scanner)
24
+
25
+ assert_array_includes Lint::MissingIndex["incidents", "crime_id"], Lint::MissingIndex["incidents", "criminal_id"], reporter.issues
26
+ end
27
+
28
+ end
29
+
30
+
31
+ class ReporterMissingTablesFunctionalTest < Test::Unit::TestCase
32
+ include CriminalDatabase
33
+ Lint = ActiveRecord::Lint
34
+ Pair = Lint::Pair
35
+
36
+ def setup
37
+ super
38
+ @connection.drop_table :criminals
39
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
40
+ Lint::load_models(@rails_root)
41
+ end
42
+
43
+ def test_should_report_missing_table_criminals
44
+ scanner = Lint::Scanner.new(@connection)
45
+ reporter = Lint::Reporter.new(scanner)
46
+
47
+ assert_array_includes Lint::MissingTable.new("criminals"), reporter.missing_tables
48
+ end
49
+
50
+ def test_issues_should_report_missing_table_criminals
51
+ scanner = Lint::Scanner.new(@connection)
52
+ reporter = Lint::Reporter.new(scanner)
53
+
54
+ assert_array_includes Lint::MissingTable.new("criminals"), reporter.issues
55
+ end
56
+
57
+ end
58
+
59
+ class ReporterMissingForeignKeysFunctionalTest < Test::Unit::TestCase
60
+ include CriminalDatabase
61
+ Lint = ActiveRecord::Lint
62
+ Pair = Lint::Pair
63
+
64
+ def setup
65
+ super
66
+ @connection.remove_column :incidents, :criminal_id
67
+ @rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
68
+ Lint::load_models(@rails_root)
69
+ end
70
+
71
+ def test_should_report_missing_table_criminals
72
+ scanner = Lint::Scanner.new(@connection)
73
+ reporter = Lint::Reporter.new(scanner)
74
+
75
+ assert_array_includes Lint::MissingForeignKey["incidents", "criminal_id"], reporter.missing_foreign_keys
76
+ end
77
+
78
+ def test_issues_should_report_missing_table_criminals
79
+ scanner = Lint::Scanner.new(@connection)
80
+ reporter = Lint::Reporter.new(scanner)
81
+
82
+ assert_array_includes Lint::MissingForeignKey["incidents", "criminal_id"], reporter.issues
83
+ end
84
+
85
+ end
@@ -0,0 +1,87 @@
1
+ require 'test/unit'
2
+
3
+ require File.join(File.dirname(__FILE__), "..", "lib", "active_record_lint")
4
+
5
+ module CriminalDatabase
6
+ def self.included(other)
7
+ other.with_temp_db do
8
+ create_table :crimes do |t|
9
+ end
10
+
11
+ create_table :criminals do |t|
12
+ end
13
+
14
+ create_table :incidents do |t|
15
+ t.references :criminal
16
+ t.references :victim
17
+ t.references :crime
18
+ end
19
+
20
+ add_index :incidents, :victim_id
21
+
22
+ create_table :victims do |t|
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ class Test::Unit::TestCase
29
+ def self.with_temp_db(&block)
30
+ include TempDB
31
+ @schema = Proc.new(&block) if block_given?
32
+ end
33
+
34
+ module TempDB
35
+ DB_PATH = "/tmp/%s.sqlite3"
36
+
37
+ def teardown_database!
38
+ File.delete(DB_PATH % [self.class.name])
39
+ end
40
+
41
+ def setup_database!
42
+ ActiveRecord::Base.establish_connection(
43
+ :adapter => "sqlite3",
44
+ :database => (DB_PATH % [self.class.name])
45
+ )
46
+ ActiveRecord::Base.logger = Logger.new(File.open("/dev/null", "w"))
47
+ @connection = ActiveRecord::Base.connection
48
+ end
49
+
50
+ def load_schema!(&block)
51
+ ActiveRecord::Schema.verbose = false
52
+ if block_given?
53
+ ActiveRecord::Schema.define(&block)
54
+ else
55
+ ActiveRecord::Schema.define(&self.class.class_eval{@schema})
56
+ end
57
+ end
58
+
59
+ def teardown
60
+ teardown_database!
61
+ end
62
+
63
+ def setup
64
+ setup_database!
65
+ load_schema!
66
+ end
67
+ end
68
+
69
+ def assert_array_equal(expected, actual, *args)
70
+ assert_equal(expected.sort, actual.sort, *args)
71
+ end
72
+
73
+ def assert_array_includes(*args)
74
+ message = "Expected <%s> to include <%s>"
75
+ expected = args.clone
76
+ actual = expected.pop
77
+
78
+ if actual.is_a? String
79
+ message = actual
80
+ actual = expected.pop
81
+ end
82
+
83
+ expected.each do |el|
84
+ assert actual.include?(el), (message % [actual.inspect, el.inspect])
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class IndexesUnitTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ include ActiveRecord::Lint
6
+
7
+ def test_should_have_correct_indexes
8
+ scanner = Scanner.new(@connection)
9
+ assert_equal([Pair["incidents", "victim_id"]], scanner.indexes)
10
+ end
11
+
12
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class ModelScanningUnitTest < Test::Unit::TestCase
4
+ include CriminalDatabase
5
+ include ActiveRecord::Lint
6
+
7
+ def setup
8
+ ActiveRecord::Lint::unload_models
9
+ super
10
+ end
11
+
12
+ def test_should_have_correct_indexes
13
+ rails_root = File.join(File.dirname(__FILE__), "..", "fixtures", "criminals")
14
+ ActiveRecord::Lint::load_models(rails_root)
15
+
16
+ scanner = ActiveRecord::Lint::Scanner.new
17
+
18
+ expected = [
19
+ Pair["incidents", "victim_id"],
20
+ Pair["incidents", "criminal_id"],
21
+ Pair["incidents", "crime_id"]
22
+ ]
23
+
24
+ assert_array_equal(expected, scanner.foreign_keys)
25
+ end
26
+
27
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(__FILE__), "..", "test_helper")
2
+
3
+ class PairUnitTest < Test::Unit::TestCase
4
+ include ActiveRecord::Lint
5
+ def test_comparison
6
+ assert_equal(Pair[1,2], Pair[1,2])
7
+ assert_equal(0, Pair[1,2] <=> Pair[1,2])
8
+ assert_equal(-1, Pair[0,2] <=> Pair[1,2])
9
+ assert_equal(1, Pair[2,2] <=> Pair[1,2])
10
+ assert_equal(-1, Pair[1,1] <=> Pair[1,2])
11
+ assert_equal(1, Pair[1,3] <=> Pair[1,2])
12
+
13
+ assert_not_equal(Pair[1,2], Pair[1,3])
14
+ assert_not_equal(Pair[1,2], Pair[2,2])
15
+ end
16
+
17
+ def test_subtraction_in_an_array
18
+ a1 = [Pair[1,2], Pair[2,2], Pair[1,1]]
19
+ a2 = [Pair[1,2], Pair[1,1]]
20
+ a3 = [Pair[2,2]]
21
+
22
+ assert_equal(a2, a1 - a3)
23
+ assert_equal(a3, a1 - a2)
24
+ assert_equal([], a1 - a2 - a3)
25
+ end
26
+
27
+ def test_hashes
28
+ assert_equal(Pair[1,2].hash, Pair[1,2].hash)
29
+ assert_equal(Pair[2,2].hash, Pair[2,2].hash)
30
+ assert_not_equal(Pair[1,2].hash, Pair[1,1].hash)
31
+ assert_not_equal(Pair[2,1].hash, Pair[1,1].hash)
32
+ end
33
+
34
+ def test_eql
35
+ assert(Pair[2,2].eql?(Pair[2,2]))
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cwninja-active_record_lint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Tom Lea
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-08 00:00:00 -08:00
13
+ default_executable: arlint
14
+ dependencies: []
15
+
16
+ description: A library to support the automatic checking for the doing of stupid things with ActiveRecord.
17
+ email: commits@tomlea.co.uk
18
+ executables:
19
+ - arlint
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - Rakefile
26
+ - README.markdown
27
+ - lib/active_record/lint/memoize.rb
28
+ - lib/active_record/lint/pairs.rb
29
+ - lib/active_record/lint/reporter.rb
30
+ - lib/active_record/lint/scanner.rb
31
+ - lib/active_record/lint.rb
32
+ - lib/active_record_lint.rb
33
+ - test/fixtures/criminals/app/models/crime.rb
34
+ - test/fixtures/criminals/app/models/criminal.rb
35
+ - test/fixtures/criminals/app/models/incident.rb
36
+ - test/fixtures/criminals/app/models/victim.rb
37
+ - test/functional/missing_foreign_keys_test.rb
38
+ - test/functional/missing_indexes_test.rb
39
+ - test/functional/missing_tables_test.rb
40
+ - test/functional/reporter_test.rb
41
+ - test/test_helper.rb
42
+ - test/unit/indexes_test.rb
43
+ - test/unit/model_scanning_test.rb
44
+ - test/unit/pair_test.rb
45
+ - bin/arlint
46
+ has_rdoc: true
47
+ homepage: http://github.com/cwninja/active_record_lint
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --line-numbers
51
+ - --inline-source
52
+ - --main
53
+ - README.markdown
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: Rails tool to find foreign keys without indexes and other common issues.
75
+ test_files:
76
+ - test/functional/missing_foreign_keys_test.rb
77
+ - test/functional/missing_indexes_test.rb
78
+ - test/functional/missing_tables_test.rb
79
+ - test/functional/reporter_test.rb
80
+ - test/unit/indexes_test.rb
81
+ - test/unit/model_scanning_test.rb
82
+ - test/unit/pair_test.rb