Commit 87b51c24 by Shu Fujita Committed by Andrew W. Lee

Refactor RSpec for AnnotateModels (1) (#726)

I refactored and structuralized RSpec test cases of AnnotateModels for readability and scalability because it was too complex to read. cf. #718 In this PR, I refactored test cases of some methods in `AnnotateModels`. I will refactor test cases of other methods in another PR.
parent 1c5deb09
......@@ -6,6 +6,20 @@ require 'active_support/core_ext/string'
require 'files'
describe AnnotateModels do # rubocop:disable Metrics/BlockLength
MAGIC_COMMENTS = [
'# encoding: UTF-8',
'# coding: UTF-8',
'# -*- coding: UTF-8 -*-',
'#encoding: utf-8',
'# encoding: utf-8',
'# -*- encoding : utf-8 -*-',
"# encoding: utf-8\n# frozen_string_literal: true",
"# frozen_string_literal: true\n# encoding: utf-8",
'# frozen_string_literal: true',
'#frozen_string_literal: false',
'# -*- frozen_string_literal : true -*-'
].freeze
def mock_index(name, params = {})
double('IndexKeyDefinition',
name: name,
......@@ -64,16 +78,71 @@ describe AnnotateModels do # rubocop:disable Metrics/BlockLength
double('Column', stubs)
end
it { expect(AnnotateModels.quote(nil)).to eql('NULL') }
it { expect(AnnotateModels.quote(true)).to eql('TRUE') }
it { expect(AnnotateModels.quote(false)).to eql('FALSE') }
it { expect(AnnotateModels.quote(25)).to eql('25') }
it { expect(AnnotateModels.quote(25.6)).to eql('25.6') }
it { expect(AnnotateModels.quote(1e-20)).to eql('1.0e-20') }
it { expect(AnnotateModels.quote(BigDecimal('1.2'))).to eql('1.2') }
it { expect(AnnotateModels.quote([BigDecimal('1.2')])).to eql(['1.2']) }
describe '.quote' do
subject do
AnnotateModels.quote(value)
end
context 'when the argument is nil' do
let(:value) { nil }
it 'returns string "NULL"' do
is_expected.to eq('NULL')
end
end
context 'when the argument is true' do
let(:value) { true }
it 'returns string "TRUE"' do
is_expected.to eq('TRUE')
end
end
context 'when the argument is false' do
let(:value) { false }
it 'returns string "FALSE"' do
is_expected.to eq('FALSE')
end
end
context 'when the argument is an integer' do
let(:value) { 25 }
it 'returns the integer as a string' do
is_expected.to eq('25')
end
end
context 'when the argument is a float number' do
context 'when the argument is like 25.6' do
let(:value) { 25.6 }
it 'returns the float number as a string' do
is_expected.to eq('25.6')
end
end
describe '#parse_options' do
context 'when the argument is like 1e-20' do
let(:value) { 1e-20 }
it 'returns the float number as a string' do
is_expected.to eq('1.0e-20')
end
end
end
context 'when the argument is a BigDecimal number' do
let(:value) { BigDecimal('1.2') }
it 'returns the float number as a string' do
is_expected.to eq('1.2')
end
end
context 'when the argument is an array' do
let(:value) { [BigDecimal('1.2')] }
it 'returns an array of which elements are converted to string' do
is_expected.to eq(['1.2'])
end
end
end
describe '.parse_options' do
let(:options) do
{
root_dir: '/root',
......@@ -81,20 +150,28 @@ describe AnnotateModels do # rubocop:disable Metrics/BlockLength
}
end
it 'sets @root_dir' do
before :each do
AnnotateModels.send(:parse_options, options)
expect(AnnotateModels.instance_variable_get(:@root_dir)).to eq('/root')
end
it 'sets @model_dir separated with a comma' do
AnnotateModels.send(:parse_options, options)
expected = [
'app/models',
'app/one',
'app/two',
'app/three'
]
expect(AnnotateModels.instance_variable_get(:@model_dir)).to eq(expected)
describe '@root_dir' do
subject do
AnnotateModels.instance_variable_get(:@root_dir)
end
it 'sets @root_dir' do
is_expected.to eq('/root')
end
end
describe '@model_dir' do
subject do
AnnotateModels.instance_variable_get(:@model_dir)
end
it 'separates option "model_dir" with commas and sets @model_dir as an array of string' do
is_expected.to eq(['app/models', 'app/one', 'app/two', 'app/three'])
end
end
end
......@@ -788,14 +865,25 @@ EOS
EOS
end
describe '#set_defaults' do
it 'should default show_complete_foreign_keys to false' do
expect(Annotate::Helpers.true?(ENV['show_complete_foreign_keys'])).to be(false)
describe '.set_defaults' do
subject do
Annotate::Helpers.true?(ENV['show_complete_foreign_keys'])
end
it 'should be able to set show_complete_foreign_keys to true' do
Annotate.set_defaults('show_complete_foreign_keys' => 'true')
expect(Annotate::Helpers.true?(ENV['show_complete_foreign_keys'])).to be(true)
context 'when default value of "show_complete_foreign_keys" is not set' do
it 'returns false' do
is_expected.to be(false)
end
end
context 'when default value of "show_complete_foreign_keys" is set' do
before do
Annotate.set_defaults('show_complete_foreign_keys' => 'true')
end
it 'returns true' do
is_expected.to be(true)
end
end
after :each do
......@@ -803,14 +891,14 @@ EOS
end
end
describe '#files_by_pattern' do
describe '.files_by_pattern' do
subject { AnnotateModels.files_by_pattern(root_directory, pattern_type, options) }
context 'when pattern_type=additional_file_patterns' do
let(:pattern_type) { 'additional_file_patterns' }
context 'when pattern_type is "additional_file_patterns"' do
let(:root_directory) { nil }
let(:pattern_type) { 'additional_file_patterns' }
context 'with additional_file_patterns' do
context 'when additional_file_patterns is specified in the options' do
let(:additional_file_patterns) do
[
'%PLURALIZED_MODEL_NAME%/**/*.rb',
......@@ -820,28 +908,28 @@ EOS
let(:options) { { additional_file_patterns: additional_file_patterns } }
it do
expect(subject).to eq(additional_file_patterns)
it 'returns additional_file_patterns in the argument "options"' do
is_expected.to eq(additional_file_patterns)
end
end
context 'without additional_file_patterns' do
context 'when additional_file_patterns is not specified is the options' do
let(:options) { {} }
it do
expect(subject).to eq([])
it 'returns an empty array' do
is_expected.to eq([])
end
end
end
end
describe '#get_patterns' do
describe '.get_patterns' do
subject { AnnotateModels.get_patterns(options, pattern_type) }
context 'when pattern_type=additional_file_patterns' do
context 'when pattern_type is "additional_file_patterns"' do
let(:pattern_type) { 'additional_file_patterns' }
context 'with additional_file_patterns' do
context 'when additional_file_patterns is specified in the options' do
let(:additional_file_patterns) do
[
'/%PLURALIZED_MODEL_NAME%/**/*.rb',
......@@ -851,16 +939,16 @@ EOS
let(:options) { { additional_file_patterns: additional_file_patterns } }
it do
expect(subject).to eq(additional_file_patterns)
it 'returns additional_file_patterns in the argument "options"' do
is_expected.to eq(additional_file_patterns)
end
end
context 'without additional_file_patterns' do
context 'when additional_file_patterns is not specified is the options' do
let(:options) { {} }
it do
expect(subject).to eq([])
it 'returns an empty array' do
is_expected.to eq([])
end
end
end
......@@ -1147,7 +1235,7 @@ EOS
end
end
describe '#get_model_files' do
describe '.get_model_files' do
subject { described_class.get_model_files(options) }
before do
......@@ -1262,432 +1350,653 @@ EOS
end
end
describe '#get_model_class' do
require 'tmpdir'
describe '.get_model_class' do # rubocop:disable Metrics/BlockLength
before :all do
require 'tmpdir'
AnnotateModels.model_dir = Dir.mktmpdir('annotate_models')
end
# TODO: use 'files' gem instead
def create(file, body = 'hi')
file_path = File.join(AnnotateModels.model_dir[0], file)
FileUtils.mkdir_p(File.dirname(file_path))
File.open(file_path, 'wb') do |f|
f.puts(body)
def create(filename, file_content)
File.join(AnnotateModels.model_dir[0], filename).tap do |path|
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'wb') do |f|
f.puts(file_content)
end
end
file_path
end
def check_class_name(file, class_name)
klass = AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], file))
before :each do
create(filename, file_content)
end
expect(klass).not_to eq(nil)
expect(klass.name).to eq(class_name)
let :klass do
AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename))
end
before :each do
AnnotateModels.model_dir = Dir.mktmpdir 'annotate_models'
context 'when class Foo is defined in "foo.rb"' do
let :filename do
'foo.rb'
end
let :file_content do
<<~EOS
class Foo < ActiveRecord::Base
end
EOS
end
it 'works' do
expect(klass.name).to eq('Foo')
end
end
it 'should work' do
create 'foo.rb', <<-EOS
class Foo < ActiveRecord::Base
context 'when class name is not capitalized normally' do
context 'when class FooWithCAPITALS is defined in "foo_with_capitals.rb"' do
let :filename do
'foo_with_capitals.rb'
end
let :file_content do
<<~EOS
class FooWithCAPITALS < ActiveRecord::Base
end
EOS
end
EOS
check_class_name 'foo.rb', 'Foo'
end
it 'should find models with non standard capitalization' do
create 'foo_with_capitals.rb', <<-EOS
class FooWithCAPITALS < ActiveRecord::Base
it 'works' do
expect(klass.name).to eq('FooWithCAPITALS')
end
EOS
check_class_name 'foo_with_capitals.rb', 'FooWithCAPITALS'
end
end
it 'should find models inside modules' do
create 'bar/foo_inside_bar.rb', <<-EOS
module Bar
class FooInsideBar < ActiveRecord::Base
end
context 'when class is defined inside module' do
context 'when class Bar::FooInsideBar is defined in "bar/foo_inside_bar.rb"' do
let :filename do
'bar/foo_inside_bar.rb'
end
EOS
check_class_name 'bar/foo_inside_bar.rb', 'Bar::FooInsideBar'
let :file_content do
<<~EOS
module Bar
class FooInsideBar < ActiveRecord::Base
end
end
EOS
end
it 'works' do
expect(klass.name).to eq('Bar::FooInsideBar')
end
end
end
it 'should find AR model when duplicated by a nested model' do
create 'foo.rb', <<-EOS
class Foo < ActiveRecord::Base
context 'when class is defined inside module and class name is not capitalized normally' do
context 'when class Bar::FooInsideCapitalsBAR is defined in "bar/foo_inside_capitals_bar.rb"' do
let :filename do
'bar/foo_inside_capitals_bar.rb'
end
EOS
create 'bar/foo.rb', <<-EOS
class Bar::Foo
let :file_content do
<<~EOS
module BAR
class FooInsideCapitalsBAR < ActiveRecord::Base
end
end
EOS
end
EOS
check_class_name 'bar/foo.rb', 'Bar::Foo'
check_class_name 'foo.rb', 'Foo'
it 'works' do
expect(klass.name).to eq('BAR::FooInsideCapitalsBAR')
end
end
end
it 'should find AR model nested inside a class' do
create 'voucher.rb', <<-EOS
class Voucher < ActiveRecord::Base
context 'when unknown macros exist in class' do
context 'when class FooWithMacro is defined in "foo_with_macro.rb"' do
let :filename do
'foo_with_macro.rb'
end
EOS
create 'voucher/foo.rb', <<-EOS
class Voucher
class Foo
end
let :file_content do
<<~EOS
class FooWithMacro < ActiveRecord::Base
acts_as_awesome :yah
end
EOS
end
EOS
check_class_name 'voucher.rb', 'Voucher'
check_class_name 'voucher/foo.rb', 'Voucher::Foo'
it 'works and does not care about known macros' do
expect(klass.name).to eq('FooWithMacro')
end
end
context 'when class name is with ALL CAPS segments' do
context 'when class is "FooWithCAPITALS" is defined in "foo_with_capitals.rb"' do
let :filename do
'foo_with_capitals.rb'
end
let :file_content do
<<~EOS
class FooWithCAPITALS < ActiveRecord::Base
acts_as_awesome :yah
end
EOS
end
it 'works' do
expect(klass.name).to eq('FooWithCAPITALS')
end
end
end
end
it 'should not care about unknown macros' do
create 'foo_with_macro.rb', <<-EOS
class FooWithMacro < ActiveRecord::Base
acts_as_awesome :yah
context 'when known macros exist in class' do
context 'when class FooWithKnownMacro is defined in "foo_with_known_macro.rb"' do
let :filename do
'foo_with_known_macro.rb'
end
EOS
check_class_name 'foo_with_macro.rb', 'FooWithMacro'
let :file_content do
<<~EOS
class FooWithKnownMacro < ActiveRecord::Base
has_many :yah
end
EOS
end
it 'works and does not care about known macros' do
expect(klass.name).to eq('FooWithKnownMacro')
end
end
end
it 'should not care about known macros' do
create('foo_with_known_macro.rb', <<-EOS)
class FooWithKnownMacro < ActiveRecord::Base
has_many :yah
context 'when the file includes invlaid multibyte chars (USASCII)' do
context 'when class FooWithUtf8 is defined in "foo_with_utf8.rb"' do
let :filename do
'foo_with_utf8.rb'
end
EOS
check_class_name 'foo_with_known_macro.rb', 'FooWithKnownMacro'
let :file_content do
<<~EOS
# encoding: utf-8
class FooWithUtf8 < ActiveRecord::Base
UTF8STRINGS = %w[résumé façon âge]
end
EOS
end
it 'works without complaining of invalid multibyte chars' do
expect(klass.name).to eq('FooWithUtf8')
end
end
end
it 'should work with class names with ALL CAPS segments' do
create('foo_with_capitals.rb', <<-EOS)
class FooWithCAPITALS < ActiveRecord::Base
acts_as_awesome :yah
context 'when non-namespaced model is inside subdirectory' do
context 'when class NonNamespacedFooInsideBar is defined in "bar/non_namespaced_foo_inside_bar.rb"' do
let :filename do
'bar/non_namespaced_foo_inside_bar.rb'
end
let :file_content do
<<~EOS
class NonNamespacedFooInsideBar < ActiveRecord::Base
end
EOS
end
it 'works' do
expect(klass.name).to eq('NonNamespacedFooInsideBar')
end
end
context 'when class name is not capitalized normally' do
context 'when class NonNamespacedFooWithCapitalsInsideBar is defined in "bar/non_namespaced_foo_with_capitals_inside_bar.rb"' do
let :filename do
'bar/non_namespaced_foo_with_capitals_inside_bar.rb'
end
let :file_content do
<<~EOS
class NonNamespacedFooWithCapitalsInsideBar < ActiveRecord::Base
end
EOS
end
EOS
check_class_name 'foo_with_capitals.rb', 'FooWithCAPITALS'
end
it 'should not complain of invalid multibyte char (USASCII)' do
create 'foo_with_utf8.rb', <<-EOS
#encoding: utf-8
class FooWithUtf8 < ActiveRecord::Base
UTF8STRINGS = %w[résumé façon âge]
it 'works' do
expect(klass.name).to eq('NonNamespacedFooWithCapitalsInsideBar')
end
end
EOS
check_class_name 'foo_with_utf8.rb', 'FooWithUtf8'
end
end
it 'should find models inside modules with non standard capitalization' do
create 'bar/foo_inside_capitals_bar.rb', <<-EOS
module BAR
class FooInsideCapitalsBAR < ActiveRecord::Base
context 'when class file is loaded twice' do
context 'when class LoadedClass is defined in "loaded_class.rb"' do
let :filename do
'loaded_class.rb'
end
let :file_content do
<<~EOS
class LoadedClass < ActiveRecord::Base
CONSTANT = 1
end
EOS
end
before :each do
path = File.expand_path(filename, AnnotateModels.model_dir[0])
Kernel.load(path)
expect(Kernel).not_to receive(:require)
end
it 'does not require model file twice' do
expect(klass.name).to eq('LoadedClass')
end
end
context 'when class is defined in a subdirectory' do
dir = Array.new(8) { (0..9).to_a.sample(random: Random.new) }.join
context "when class SubdirLoadedClass is defined in \"#{dir}/subdir_loaded_class.rb\"" do
before :each do
$LOAD_PATH.unshift(File.join(AnnotateModels.model_dir[0], dir))
path = File.expand_path(filename, AnnotateModels.model_dir[0])
Kernel.load(path)
expect(Kernel).not_to receive(:require)
end
let :filename do
"#{dir}/subdir_loaded_class.rb"
end
let :file_content do
<<~EOS
class SubdirLoadedClass < ActiveRecord::Base
CONSTANT = 1
end
EOS
end
it 'does not require model file twice' do
expect(klass.name).to eq('SubdirLoadedClass')
end
end
EOS
check_class_name 'bar/foo_inside_capitals_bar.rb', 'BAR::FooInsideCapitalsBAR'
end
end
it 'should find non-namespaced models inside subdirectories' do
create 'bar/non_namespaced_foo_inside_bar.rb', <<-EOS
class NonNamespacedFooInsideBar < ActiveRecord::Base
context 'when two class exist' do
before :each do
create(filename_2, file_content_2)
end
context 'the base names are duplicated' do
let :filename do
'foo.rb'
end
let :file_content do
<<-EOS
class Foo < ActiveRecord::Base
end
EOS
end
EOS
check_class_name 'bar/non_namespaced_foo_inside_bar.rb', 'NonNamespacedFooInsideBar'
end
it 'should find non-namespaced models with non standard capitalization inside subdirectories' do
create 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', <<-EOS
class NonNamespacedFooWithCapitalsInsideBar < ActiveRecord::Base
let :filename_2 do
'bar/foo.rb'
end
EOS
check_class_name 'bar/non_namespaced_foo_with_capitals_inside_bar.rb', 'NonNamespacedFooWithCapitalsInsideBar'
end
it 'should allow known macros' do
create('foo_with_known_macro.rb', <<-EOS)
class FooWithKnownMacro < ActiveRecord::Base
has_many :yah
let :file_content_2 do
<<-EOS
class Bar::Foo
end
EOS
end
EOS
expect(capturing(:stderr) do
check_class_name 'foo_with_known_macro.rb', 'FooWithKnownMacro'
end).to eq('')
end
it 'should not require model files twice' do
create 'loaded_class.rb', <<-EOS
class LoadedClass < ActiveRecord::Base
CONSTANT = 1
let :klass_2 do
AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename_2))
end
EOS
path = File.expand_path('loaded_class', AnnotateModels.model_dir[0])
Kernel.load "#{path}.rb"
expect(Kernel).not_to receive(:require)
expect(capturing(:stderr) do
check_class_name 'loaded_class.rb', 'LoadedClass'
end).to be_blank
end
it 'finds valid model' do
expect(klass.name).to eq('Foo')
expect(klass_2.name).to eq('Bar::Foo')
end
end
it 'should not require model files twice which is inside a subdirectory' do
dir = Array.new(8) { (0..9).to_a.sample(random: Random.new) }.join
$LOAD_PATH.unshift(File.join(AnnotateModels.model_dir[0], dir))
context 'one of the classes is nested in another class' do
let :filename do
'voucher.rb'
end
create "#{dir}/subdir_loaded_class.rb", <<-EOS
class SubdirLoadedClass < ActiveRecord::Base
CONSTANT = 1
let :file_content do
<<-EOS
class Voucher < ActiveRecord::Base
end
EOS
end
EOS
path = File.expand_path("#{dir}/subdir_loaded_class", AnnotateModels.model_dir[0])
Kernel.load "#{path}.rb"
expect(Kernel).not_to receive(:require)
expect(capturing(:stderr) do
check_class_name "#{dir}/subdir_loaded_class.rb", 'SubdirLoadedClass'
end).to be_blank
end
end
let :filename_2 do
'voucher/foo.rb'
end
describe '#remove_annotation_of_file' do
require 'tmpdir'
let :file_content_2 do
<<~EOS
class Voucher
class Foo
end
end
EOS
end
def create(file, body = 'hi')
path = File.join(@dir, file)
File.open(path, 'w') do |f|
f.puts(body)
let :klass_2 do
AnnotateModels.get_model_class(File.join(AnnotateModels.model_dir[0], filename_2))
end
it 'finds valid model' do
expect(klass.name).to eq('Voucher')
expect(klass_2.name).to eq('Voucher::Foo')
end
end
end
end
path
describe '.remove_annotation_of_file' do
subject do
AnnotateModels.remove_annotation_of_file(path)
end
def content(path)
File.read(path)
let :tmpdir do
require 'tmpdir'
Dir.mktmpdir('annotate_models')
end
before :each do
@dir = Dir.mktmpdir 'annotate_models'
let :path do
File.join(tmpdir, filename).tap do |path|
File.open(path, 'w') do |f|
f.puts(file_content)
end
end
end
it 'should remove before annotate' do
path = create 'before.rb', <<-EOS
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
let :file_content_after_removal do
subject
File.read(path)
end
class Foo < ActiveRecord::Base
end
let :expected_result do
<<~EOS
class Foo < ActiveRecord::Base
end
EOS
end
AnnotateModels.remove_annotation_of_file(path)
context 'when annotation is before main content' do
let :filename do
'before.rb'
end
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
let :file_content do
<<~EOS
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
class Foo < ActiveRecord::Base
end
EOS
end
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'should remove annotate if CRLF is used for line breaks' do
path = create 'before.rb', <<-EOS
# == Schema Information
#
# Table name: foo\r\n#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
\r\n
class Foo < ActiveRecord::Base
end
EOS
context 'when annotation is before main content and CRLF is used for line breaks' do
let :filename do
'before.rb'
end
AnnotateModels.remove_annotation_of_file(path)
let :file_content do
<<~EOS
# == Schema Information
#
# Table name: foo\r\n#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
\r\n
class Foo < ActiveRecord::Base
end
EOS
end
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'should remove after annotate' do
path = create 'after.rb', <<-EOS
class Foo < ActiveRecord::Base
end
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
context 'when annotation is before main content and with opening wrapper' do
let :filename do
'opening_wrapper.rb'
end
EOS
let :file_content do
<<~EOS
# wrapper
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
class Foo < ActiveRecord::Base
end
EOS
end
AnnotateModels.remove_annotation_of_file(path)
subject do
AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper')
end
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'should remove opening wrapper' do
path = create 'opening_wrapper.rb', <<-EOS
# wrapper
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
context 'when annotation is before main content and with opening wrapper' do
let :filename do
'opening_wrapper.rb'
end
class Foo < ActiveRecord::Base
end
EOS
let :file_content do
<<~EOS
# wrapper\r\n# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
class Foo < ActiveRecord::Base
end
EOS
end
AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper')
subject do
AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper')
end
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'should remove wrapper if CRLF is used for line breaks' do
path = create 'opening_wrapper.rb', <<-EOS
# wrapper\r\n# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
context 'when annotation is after main content' do
let :filename do
'after.rb'
end
class Foo < ActiveRecord::Base
end
EOS
let :file_content do
<<~EOS
class Foo < ActiveRecord::Base
end
AnnotateModels.remove_annotation_of_file(path, wrapper_open: 'wrapper')
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
EOS
end
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'should remove closing wrapper' do
path = create 'closing_wrapper.rb', <<-EOS
class Foo < ActiveRecord::Base
end
context 'when annotation is after main content and with closing wrapper' do
let :filename do
'closing_wrapper.rb'
end
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
# wrapper
let :file_content do
<<~EOS
class Foo < ActiveRecord::Base
end
EOS
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
# wrapper
AnnotateModels.remove_annotation_of_file(path, wrapper_close: 'wrapper')
EOS
end
expect(content(path)).to eq <<-EOS
class Foo < ActiveRecord::Base
end
EOS
subject do
AnnotateModels.remove_annotation_of_file(path, wrapper_close: 'wrapper')
end
it 'removes annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
it 'does not change file with #SkipSchemaAnnotations' do
content = <<-EOS
# -*- SkipSchemaAnnotations
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
context 'when annotation is before main content and with comment "-*- SkipSchemaAnnotations"' do
let :filename do
'skip.rb'
end
class Foo < ActiveRecord::Base
end
EOS
let :file_content do
<<~EOS
# -*- SkipSchemaAnnotations
# == Schema Information
#
# Table name: foo
#
# id :integer not null, primary key
# created_at :datetime
# updated_at :datetime
#
class Foo < ActiveRecord::Base
end
EOS
end
path = create 'skip.rb', content
let :expected_result do
file_content
end
AnnotateModels.remove_annotation_of_file(path)
expect(content(path)).to eq(content)
it 'does not remove annotation' do
expect(file_content_after_removal).to eq expected_result
end
end
end
describe '#resolve_filename' do
it 'should return the test path for a model' do
filename_template = 'test/unit/%MODEL_NAME%_test.rb'
model_name = 'example_model'
table_name = 'example_models'
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/unit/example_model_test.rb'
describe '.resolve_filename' do
subject do
AnnotateModels.resolve_filename(filename_template, model_name, table_name)
end
it 'should return the additional glob' do
filename_template = '/foo/bar/%MODEL_NAME%/testing.rb'
model_name = 'example_model'
table_name = 'example_models'
context 'When model_name is "example_model" and table_name is "example_models"' do
let(:model_name) { 'example_model' }
let(:table_name) { 'example_models' }
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq '/foo/bar/example_model/testing.rb'
end
context "when filename_template is 'test/unit/%MODEL_NAME%_test.rb'" do
let(:filename_template) { 'test/unit/%MODEL_NAME%_test.rb' }
it 'should return the additional glob' do
filename_template = '/foo/bar/%PLURALIZED_MODEL_NAME%/testing.rb'
model_name = 'example_model'
table_name = 'example_models'
it 'returns the test path for a model' do
is_expected.to eq 'test/unit/example_model_test.rb'
end
end
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq '/foo/bar/example_models/testing.rb'
end
context "when filename_template is '/foo/bar/%MODEL_NAME%/testing.rb'" do
let(:filename_template) { '/foo/bar/%MODEL_NAME%/testing.rb' }
it 'should return the fixture path for a model' do
filename_template = 'test/fixtures/%TABLE_NAME%.yml'
model_name = 'example_model'
table_name = 'example_models'
it 'returns the additional glob' do
is_expected.to eq '/foo/bar/example_model/testing.rb'
end
end
context "when filename_template is '/foo/bar/%PLURALIZED_MODEL_NAME%/testing.rb'" do
let(:filename_template) { '/foo/bar/%PLURALIZED_MODEL_NAME%/testing.rb' }
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/fixtures/example_models.yml'
it 'returns the additional glob' do
is_expected.to eq '/foo/bar/example_models/testing.rb'
end
end
context "when filename_template is 'test/fixtures/%TABLE_NAME%.yml'" do
let(:filename_template) { 'test/fixtures/%TABLE_NAME%.yml' }
it 'returns the fixture path for a model' do
is_expected.to eq 'test/fixtures/example_models.yml'
end
end
end
it 'should return the fixture path for a nested model' do
filename_template = 'test/fixtures/%PLURALIZED_MODEL_NAME%.yml'
model_name = 'parent/child'
table_name = 'parent_children'
context 'When model_name is "parent/child" and table_name is "parent_children"' do
let(:model_name) { 'parent/child' }
let(:table_name) { 'parent_children' }
context "when filename_template is 'test/fixtures/%PLURALIZED_MODEL_NAME%.yml'" do
let(:filename_template) { 'test/fixtures/%PLURALIZED_MODEL_NAME%.yml' }
filename = AnnotateModels.resolve_filename(filename_template, model_name, table_name)
expect(filename). to eq 'test/fixtures/parent/children.yml'
it 'returns the fixture path for a nested model' do
is_expected.to eq 'test/fixtures/parent/children.yml'
end
end
end
end
describe 'annotating a file' do
before do
@model_dir = Dir.mktmpdir('annotate_models')
(@model_file_name, @file_content) = write_model 'user.rb', <<-EOS
class User < ActiveRecord::Base
end
(@model_file_name, @file_content) = write_model 'user.rb', <<~EOS
class User < ActiveRecord::Base
end
EOS
@klass = mock_class(:users,
......@@ -1720,22 +2029,6 @@ end
Annotate::Constants::PATH_OPTIONS.each { |key| ENV[key.to_s] = '' }
end
def magic_comments_list_each
[
'# encoding: UTF-8',
'# coding: UTF-8',
'# -*- coding: UTF-8 -*-',
'#encoding: utf-8',
'# encoding: utf-8',
'# -*- encoding : utf-8 -*-',
"# encoding: utf-8\n# frozen_string_literal: true",
"# frozen_string_literal: true\n# encoding: utf-8",
'# frozen_string_literal: true',
'#frozen_string_literal: false',
'# -*- frozen_string_literal : true -*-'
].each { |magic_comment| yield magic_comment }
end
['before', :before, 'top', :top].each do |position|
it "should put annotation before class if :position == #{position}" do
annotate_one_file position: position
......@@ -1854,9 +2147,9 @@ end
end
it 'works with namespaced models (i.e. models inside modules/subdirectories)' do
(model_file_name, file_content) = write_model 'foo/user.rb', <<-EOS
class Foo::User < ActiveRecord::Base
end
(model_file_name, file_content) = write_model 'foo/user.rb', <<~EOS
class Foo::User < ActiveRecord::Base
end
EOS
klass = mock_class(:'foo_users',
......@@ -1871,11 +2164,11 @@ end
end
it 'should not touch magic comments' do
magic_comments_list_each do |magic_comment|
write_model 'user.rb', <<-EOS
#{magic_comment}
class User < ActiveRecord::Base
end
MAGIC_COMMENTS.each do |magic_comment|
write_model 'user.rb', <<~EOS
#{magic_comment}
class User < ActiveRecord::Base
end
EOS
annotate_one_file position: :before
......@@ -1891,7 +2184,7 @@ end
it 'adds an empty line between magic comments and annotation (position :before)' do
content = "class User < ActiveRecord::Base\nend\n"
magic_comments_list_each do |magic_comment|
MAGIC_COMMENTS.each do |magic_comment|
model_file_name, = write_model 'user.rb', "#{magic_comment}\n#{content}"
annotate_one_file position: :before
......@@ -1903,7 +2196,7 @@ end
it 'only keeps a single empty line around the annotation (position :before)' do
content = "class User < ActiveRecord::Base\nend\n"
magic_comments_list_each do |magic_comment|
MAGIC_COMMENTS.each do |magic_comment|
schema_info = AnnotateModels.get_schema_info(@klass, '== Schema Info')
model_file_name, = write_model 'user.rb', "#{magic_comment}\n\n\n\n#{content}"
......@@ -1915,7 +2208,7 @@ end
it 'does not change whitespace between magic comments and model file content (position :after)' do
content = "class User < ActiveRecord::Base\nend\n"
magic_comments_list_each do |magic_comment|
MAGIC_COMMENTS.each do |magic_comment|
model_file_name, = write_model 'user.rb', "#{magic_comment}\n#{content}"
annotate_one_file position: :after
......@@ -1929,7 +2222,7 @@ end
before do
allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil)
write_model('user.rb', <<-EOS)
write_model('user.rb', <<~EOS)
class User < ActiveRecord::Base
raise "oops"
end
......@@ -1959,7 +2252,7 @@ end
before do
allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil)
write_model('user.rb', <<-EOS)
write_model('user.rb', <<~EOS)
class User < ActiveRecord::Base
raise "oops"
end
......@@ -2012,12 +2305,14 @@ end
allow(Foo).to receive(:table_exists?) { false }
end
subject do
AnnotateModels.annotate_model_file([], 'foo.rb', nil, {})
end
after { Object.send :remove_const, 'Foo' }
it 'skips attempt to annotate if no table exists for model' do
annotate_model_file = AnnotateModels.annotate_model_file([], 'foo.rb', nil, {})
expect(annotate_model_file).to eq nil
is_expected.to eq nil
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment