diff --git a/.rubocop.yml b/.rubocop.yml index 96bc8b6..ba5bb34 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +require: + - rubocop-rspec + AllCops: NewCops: enable @@ -20,3 +23,18 @@ Metrics/MethodLength: Style/Documentation: Enabled: false + +RSpec/ContextWording: + Enabled: false +RSpec/ExampleLength: + Enabled: false +RSpec/MessageSpies: + Enabled: false +RSpec/MultipleExpectations: + Enabled: false +RSpec/NamedSubject: + Enabled: false +RSpec/NestedGroups: + Enabled: false +RSpec/SubjectStub: + Enabled: false diff --git a/Gemfile b/Gemfile index f923b7e..c3cc67d 100644 --- a/Gemfile +++ b/Gemfile @@ -10,3 +10,4 @@ gem "rake", "~> 13.0" gem "rspec", "~> 3.0" gem "rubocop", "~> 1.21" +gem "rubocop-rspec", "~> 2.22.0", require: false diff --git a/Gemfile.lock b/Gemfile.lock index ec67b26..024b386 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -46,6 +46,14 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.24.1) parser (>= 3.1.1.0) + rubocop-capybara (2.18.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.23.1) + rubocop (~> 1.33) + rubocop-rspec (2.22.0) + rubocop (~> 1.33) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) ruby-progressbar (1.11.0) unicode-display_width (2.4.2) @@ -57,6 +65,7 @@ DEPENDENCIES rake (~> 13.0) rspec (~> 3.0) rubocop (~> 1.21) + rubocop-rspec (~> 2.22.0) slither! BUNDLED WITH diff --git a/spec/column_spec.rb b/spec/slither/column_spec.rb similarity index 96% rename from spec/column_spec.rb rename to spec/slither/column_spec.rb index f6f3614..8e63ed5 100644 --- a/spec/column_spec.rb +++ b/spec/slither/column_spec.rb @@ -1,346 +1,345 @@ -# frozen_string_literal: true - -RSpec.describe Slither::Column do - subject { described_class.new(name, length, **options) } - - let(:name) { :id } - let(:length) { 5 } - let(:options) { {} } - - describe "#initialize" do - it "have a name" do - expect(subject.name).to eq(name) - end - - it "have a length" do - expect(subject.length).to eq(length) - end - - it "have a default padding" do - expect(subject.padding).to eq(:space) - end - - it "have a default alignment" do - expect(subject.alignment).to eq(:right) - end - - # WHY THO? - it "have a default formatter" do - expect(subject.send(:formatter)).to eq("%5s") - end - - it "have a default unpacker value" do - expect(subject.send(:unpacker)).to eq("A5") - end - - context "when specifying an alignment" do - let(:options) { { align: alignment } } - let(:alignment) { :left } - - it "override the default one" do - expect(subject.alignment).to eq(alignment) - end - - context "when alignment is not left nor right" do - let(:alignment) { :up } - - it "raises error" do - expect do - subject - end.to raise_error(ArgumentError) - end - end - end - - context "when specifying padding" do - let(:options) { { padding: padding } } - let(:padding) { :zero } - - it "override the default one" do - expect(subject.padding).to eq(padding) - end - - context "when padding is not space nor zero" do - let(:padding) { :up } - - it "raises error" do - expect do - subject - end.to raise_error(ArgumentError) - end - end - end - end - - describe "#parse" do - context "when using the default (string) type" do - let(:parse_collection) do - [ - { value: " name ", result: "name" }, - { value: " 234", result: "234" }, - { value: "000000234", result: "000000234" }, - { value: "12.34", result: "12.34" } - ] - end - - it "parse the expected values" do - parse_collection.each do |to_parse| - expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) - end - end - end - - context "when type is integer" do - let(:options) { { type: :integer } } - - let(:parse_collection) do - [ - { value: "234 ", result: 234 }, - { value: " 234", result: 234 }, - { value: "00000234", result: 234 }, - { value: "Ryan ", result: 0 }, - { value: "00023.45", result: 23 } - ] - end - - it "parse the expected values" do - parse_collection.each do |to_parse| - expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) - end - end - end - - context "when type is float" do - let(:options) { { type: :float } } - - let(:parse_collection) do - [ - { value: " 234.45", result: 234.45 }, - { value: "234.5600", result: 234.56 }, - { value: " 234", result: 234.0 }, - { value: "00000234", result: 234.0 }, - { value: "Ryan ", result: 0 }, - { value: "00023.45", result: 23.45 } - ] - end - - it "parse the expected values" do - parse_collection.each do |to_parse| - expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) - end - end - end - - context "when type is money_with_implied_decimal" do - let(:options) { { type: :money_with_implied_decimal } } - - it "parse the expected value" do - expect(subject.parse(" 23445")).to eq(234.45) - end - end - - context "when type is date" do - let(:options) { { type: :date } } - - it "parse the expected value" do - date = "2023-03-10" - - result = subject.parse(date) - - expect(result).to be_a(Date) - expect(result.to_s).to eq(date) - end - - context "and date format is specified" do - let(:options) { { type: :date, format: "%m%d%Y" } } - - it "parse the expected value" do - date = "03102023" - - result = subject.parse(date) - - expect(result).to be_a(Date) - expect(result.to_s).to eq("2023-03-10") - end - end - end - end - - describe "#format" do - context "when applying formatting options" do - context "using left alignment" do - let(:options) { { align: :left } } - - it "uses a proper formatter" do - expect(subject.send(:formatter)).to eq("%-5s") - end - - it "respect the format" do - expect(subject.format(25)).to eq("25 ") - end - end - - context "using right alignment" do - let(:options) { { align: :right } } - - it "respect the format" do - expect(subject.format(25)).to eq(" 25") - end - end - - context "using padding with spaces" do - let(:options) { { padding: :space } } - - it "respect the format" do - expect(subject.format(25)).to eq(' 25') - end - end - - context "using padding with zeros with integer types" do - let(:options) { { type: :integer, padding: :zero } } - - it "respect the format" do - expect(subject.format(25)).to eq("00025") - end - end - - context "using padding with zeros with float type" do - let(:options) { { type: :float, padding: :zero, align: align } } - - context "right aligned" do - let(:align) { :right } - - it "respect the format" do - expect(subject.format(4.45)).to eq("04.45") - end - end - - context "left aligned" do - let(:align) { :left } - - it "respect the format" do - expect(subject.format(4.45)).to eq("4.450") - end - end - end - end - - context "when formatting files/strings" do - it "parse the string" do - expect(subject.format("Bill")).to eq(" Bill") - end - - context "when string is too long" do - it "raises an error" do - value = "Billllllllllll" - - expect do - subject.format(value) - end.to raise_error(Slither::FormattedStringExceedsLengthError) - end - end - - context "truncate is true" do - let(:options) { { truncate: true, align: align } } - let(:value) { "This is too long" } - - context "left aligned" do - let(:align) { :left } - - it "truncate the string left-aligned" do - expect(subject.format(value)).to eq("This ") - end - end - - context "right aligned" do - let(:align) { :right } - - it "truncate the string right-aligned" do - expect(subject.format(value)).to eq(" long") - end - end - end - - context "when type is integer" do - let(:options) { { type: :integer } } - - it "supports the type" do - expect(subject.format(234)).to eq(" 234") - expect(subject.format("234")).to eq(" 234") - end - end - - context "when type is float" do - let(:options) { { type: :float } } - - it "supports the type" do - expect(subject.format(23.4)).to eq(" 23.4") - expect(subject.format("2.2000")).to eq(" 2.2") - expect(subject.format("3")).to eq(" 3.0") - end - - context "with format" do - let(:options) { { type: :float, format: "%.3f"} } - let(:length) { 10 } - - it "support the type with its format" do - expect(subject.format(234.45)).to eq(" 234.450") - expect(subject.format('234.4500')).to eq(" 234.450") - expect(subject.format('3')).to eq(" 3.000") - end - - context "alignment and padding" do - it "supports the type with the extra options" do - [ - { format: "%.2f", aligment: :left, padding: :zero, value: 234.45, result: "234.450000" }, - { format: "%.2f", aligment: :right, padding: :zero, value: "234.400", result: "0000234.40" }, - { format: "%.4f", aligment: :left, padding: :space, value: "3", result: "3.0000 " } - ].each do |obj| - sub = described_class.new( - :amount, - 10, - type: :float, - format: obj[:format], - align: obj[:aligment], - padding: obj[:padding] - ) - - expect(sub.format(obj[:value])).to eq(obj[:result]) - end - end - end - end - end - - context "when type is money_with_implied_decimal" do - let(:options) { { type: :money_with_implied_decimal } } - let(:length) { 10 } - - it "supports the type" do - expect(subject.format(234.450)).to eq(" 23445") - expect(subject.format(12.34)).to eq(" 1234") - end - end - - context "when type is date" do - let(:options) { { type: :date, **extra_opts } } - let(:extra_opts) { {} } - let(:length) { 10 } - let(:date) { Date.new(2009, 8, 22) } - - it "supports the type" do - expect(subject.format(date)).to eq("2009-08-22") - end - - context "and format is specified" do - let(:extra_opts) { { format: "%m%d%Y" } } - - it "supports the type with its format" do - - expect(subject.format(date)).to eq(" 08222009") - end - end - end - end - end -end +# frozen_string_literal: true + +RSpec.describe Slither::Column do + subject { described_class.new(name, length, **options) } + + let(:name) { :id } + let(:length) { 5 } + let(:options) { {} } + + describe "#initialize" do + it "have a name" do + expect(subject.name).to eq(name) + end + + it "have a length" do + expect(subject.length).to eq(length) + end + + it "have a default padding" do + expect(subject.padding).to eq(:space) + end + + it "have a default alignment" do + expect(subject.alignment).to eq(:right) + end + + # WHY THO? + it "have a default formatter" do + expect(subject.send(:formatter)).to eq("%5s") + end + + it "have a default unpacker value" do + expect(subject.send(:unpacker)).to eq("A5") + end + + context "when specifying an alignment" do + let(:options) { { align: alignment } } + let(:alignment) { :left } + + it "override the default one" do + expect(subject.alignment).to eq(alignment) + end + + context "when alignment is not left nor right" do + let(:alignment) { :up } + + it "raises error" do + expect do + subject + end.to raise_error(ArgumentError) + end + end + end + + context "when specifying padding" do + let(:options) { { padding: padding } } + let(:padding) { :zero } + + it "override the default one" do + expect(subject.padding).to eq(padding) + end + + context "when padding is not space nor zero" do + let(:padding) { :up } + + it "raises error" do + expect do + subject + end.to raise_error(ArgumentError) + end + end + end + end + + describe "#parse" do + context "when using the default (string) type" do + let(:parse_collection) do + [ + { value: " name ", result: "name" }, + { value: " 234", result: "234" }, + { value: "000000234", result: "000000234" }, + { value: "12.34", result: "12.34" } + ] + end + + it "parse the expected values" do + parse_collection.each do |to_parse| + expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) + end + end + end + + context "when type is integer" do + let(:options) { { type: :integer } } + + let(:parse_collection) do + [ + { value: "234 ", result: 234 }, + { value: " 234", result: 234 }, + { value: "00000234", result: 234 }, + { value: "Ryan ", result: 0 }, + { value: "00023.45", result: 23 } + ] + end + + it "parse the expected values" do + parse_collection.each do |to_parse| + expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) + end + end + end + + context "when type is float" do + let(:options) { { type: :float } } + + let(:parse_collection) do + [ + { value: " 234.45", result: 234.45 }, + { value: "234.5600", result: 234.56 }, + { value: " 234", result: 234.0 }, + { value: "00000234", result: 234.0 }, + { value: "Ryan ", result: 0 }, + { value: "00023.45", result: 23.45 } + ] + end + + it "parse the expected values" do + parse_collection.each do |to_parse| + expect(subject.parse(to_parse[:value])).to eq(to_parse[:result]) + end + end + end + + context "when type is money_with_implied_decimal" do + let(:options) { { type: :money_with_implied_decimal } } + + it "parse the expected value" do + expect(subject.parse(" 23445")).to eq(234.45) + end + end + + context "when type is date" do + let(:options) { { type: :date } } + + it "parse the expected value" do + date = "2023-03-10" + + result = subject.parse(date) + + expect(result).to be_a(Date) + expect(result.to_s).to eq(date) + end + + context "and date format is specified" do + let(:options) { { type: :date, format: "%m%d%Y" } } + + it "parse the expected value" do + date = "03102023" + + result = subject.parse(date) + + expect(result).to be_a(Date) + expect(result.to_s).to eq("2023-03-10") + end + end + end + end + + describe "#format" do + context "when applying formatting options" do + context "using left alignment" do + let(:options) { { align: :left } } + + it "uses a proper formatter" do + expect(subject.send(:formatter)).to eq("%-5s") + end + + it "respect the format" do + expect(subject.format(25)).to eq("25 ") + end + end + + context "using right alignment" do + let(:options) { { align: :right } } + + it "respect the format" do + expect(subject.format(25)).to eq(" 25") + end + end + + context "using padding with spaces" do + let(:options) { { padding: :space } } + + it "respect the format" do + expect(subject.format(25)).to eq(' 25') + end + end + + context "using padding with zeros with integer types" do + let(:options) { { type: :integer, padding: :zero } } + + it "respect the format" do + expect(subject.format(25)).to eq("00025") + end + end + + context "using padding with zeros with float type" do + let(:options) { { type: :float, padding: :zero, align: align } } + + context "right aligned" do + let(:align) { :right } + + it "respect the format" do + expect(subject.format(4.45)).to eq("04.45") + end + end + + context "left aligned" do + let(:align) { :left } + + it "respect the format" do + expect(subject.format(4.45)).to eq("4.450") + end + end + end + end + + context "when formatting files/strings" do + it "parse the string" do + expect(subject.format("Bill")).to eq(" Bill") + end + + context "when string is too long" do + it "raises an error" do + value = "Billllllllllll" + + expect do + subject.format(value) + end.to raise_error(Slither::FormattedStringExceedsLengthError) + end + end + + context "truncate is true" do + let(:options) { { truncate: true, align: align } } + let(:value) { "This is too long" } + + context "left aligned" do + let(:align) { :left } + + it "truncate the string left-aligned" do + expect(subject.format(value)).to eq("This ") + end + end + + context "right aligned" do + let(:align) { :right } + + it "truncate the string right-aligned" do + expect(subject.format(value)).to eq(" long") + end + end + end + + context "when type is integer" do + let(:options) { { type: :integer } } + + it "supports the type" do + expect(subject.format(234)).to eq(" 234") + expect(subject.format("234")).to eq(" 234") + end + end + + context "when type is float" do + let(:options) { { type: :float } } + + it "supports the type" do + expect(subject.format(23.4)).to eq(" 23.4") + expect(subject.format("2.2000")).to eq(" 2.2") + expect(subject.format("3")).to eq(" 3.0") + end + + context "with format" do + let(:options) { { type: :float, format: "%.3f"} } + let(:length) { 10 } + + it "support the type with its format" do + expect(subject.format(234.45)).to eq(" 234.450") + expect(subject.format('234.4500')).to eq(" 234.450") + expect(subject.format('3')).to eq(" 3.000") + end + + context "alignment and padding" do + it "supports the type with the extra options" do + [ + { format: "%.2f", aligment: :left, padding: :zero, value: 234.45, result: "234.450000" }, + { format: "%.2f", aligment: :right, padding: :zero, value: "234.400", result: "0000234.40" }, + { format: "%.4f", aligment: :left, padding: :space, value: "3", result: "3.0000 " } + ].each do |obj| + sub = described_class.new( + :amount, + 10, + type: :float, + format: obj[:format], + align: obj[:aligment], + padding: obj[:padding] + ) + + expect(sub.format(obj[:value])).to eq(obj[:result]) + end + end + end + end + end + + context "when type is money_with_implied_decimal" do + let(:options) { { type: :money_with_implied_decimal } } + let(:length) { 10 } + + it "supports the type" do + expect(subject.format(234.450)).to eq(" 23445") + expect(subject.format(12.34)).to eq(" 1234") + end + end + + context "when type is date" do + let(:options) { { type: :date, **extra_opts } } + let(:extra_opts) { {} } + let(:length) { 10 } + let(:date) { Date.new(2009, 8, 22) } + + it "supports the type" do + expect(subject.format(date)).to eq("2009-08-22") + end + + context "and format is specified" do + let(:extra_opts) { { format: "%m%d%Y" } } + + it "supports the type with its format" do + expect(subject.format(date)).to eq(" 08222009") + end + end + end + end + end +end diff --git a/spec/definition_spec.rb b/spec/slither/definition_spec.rb similarity index 95% rename from spec/definition_spec.rb rename to spec/slither/definition_spec.rb index ed21b35..f2cfbd6 100644 --- a/spec/definition_spec.rb +++ b/spec/slither/definition_spec.rb @@ -1,107 +1,107 @@ -# frozen_string_literal: true - -RSpec.describe Slither::Definition do - describe "when specifying alignment" do - subject { described_class } - - it "have an alignment option" do - definition = subject.new(align: :left) - - expect(definition.options[:align]).to eq(:left) - end - - it "default to being right aligned" do - definition = subject.new - - expect(definition.options[:align]).to eq(:right) - end - - context "when messing with the section alignment" do - subject { described_class.new } - - it "defaults to :right if is not specified" do - subject.section("name") {} - - section = subject.sections.first - - expect(section.options[:align]).to eq(:right) - end - - it "override default if :align is passed to the section" do - subject.section("name", align: :left) {} - - section = subject.sections.first - - expect(section.options[:align]).to eq(:left) - end - end - end - - describe "#section" do - subject { described_class.new } - - it "create and yield a new section object" do - yielded = nil - - subject.section :header do |section| - yielded = section - end - - expect(yielded).to be_a(Slither::Section) - expect(subject.sections.first).to eq(yielded) - end - - it "magically build a section from an unknown method" do - new_section = nil - - subject.new_section do |section| - new_section = section - end - - expect(new_section).to be_a(Slither::Section) - expect(new_section.name).to eq(:new_section) - end - - it "does not create duplicate section names" do - subject.section(:header) {} - - expect do - subject.section(:header) {} - end.to raise_error(ArgumentError) - end - - it "throw an error if a reserved section name is used" do - reserved_name = Slither::Section::RESERVED_NAMES.first - - expect do - subject.section(reserved_name) - end.to raise_error(ArgumentError) - end - end - - describe "#template" do - subject { described_class.new } - - it "create a new section" do - expect(Slither::Section).to receive(:new) - - subject.template(:row) {} - end - - it "add a section to the templates collection" do - expect do - subject.template(:row) {} - end.to change { subject.templates.count }.by(1) - end - - it "yield the new section" do - yielded = nil - - subject.template(:row) do |section| - yielded = section - end - - expect(yielded).to be_a(Slither::Section) - end - end -end +# frozen_string_literal: true + +RSpec.describe Slither::Definition do + describe "when specifying alignment" do + subject { described_class } + + it "have an alignment option" do + definition = subject.new(align: :left) + + expect(definition.options[:align]).to eq(:left) + end + + it "default to being right aligned" do + definition = subject.new + + expect(definition.options[:align]).to eq(:right) + end + + context "when messing with the section alignment" do + subject { described_class.new } + + it "defaults to :right if is not specified" do + subject.section("name") {} + + section = subject.sections.first + + expect(section.options[:align]).to eq(:right) + end + + it "override default if :align is passed to the section" do + subject.section("name", align: :left) {} + + section = subject.sections.first + + expect(section.options[:align]).to eq(:left) + end + end + end + + describe "#section" do + subject { described_class.new } + + it "create and yield a new section object" do + yielded = nil + + subject.section :header do |section| + yielded = section + end + + expect(yielded).to be_a(Slither::Section) + expect(subject.sections.first).to eq(yielded) + end + + it "magically build a section from an unknown method" do + new_section = nil + + subject.new_section do |section| + new_section = section + end + + expect(new_section).to be_a(Slither::Section) + expect(new_section.name).to eq(:new_section) + end + + it "does not create duplicate section names" do + subject.section(:header) {} + + expect do + subject.section(:header) {} + end.to raise_error(ArgumentError) + end + + it "throw an error if a reserved section name is used" do + reserved_name = Slither::Section::RESERVED_NAMES.first + + expect do + subject.section(reserved_name) + end.to raise_error(ArgumentError) + end + end + + describe "#template" do + subject { described_class.new } + + it "create a new section" do + expect(Slither::Section).to receive(:new) + + subject.template(:row) {} + end + + it "add a section to the templates collection" do + expect do + subject.template(:row) {} + end.to change { subject.templates.count }.by(1) + end + + it "yield the new section" do + yielded = nil + + subject.template(:row) do |section| + yielded = section + end + + expect(yielded).to be_a(Slither::Section) + end + end +end diff --git a/spec/generator_spec.rb b/spec/slither/generator_spec.rb similarity index 96% rename from spec/generator_spec.rb rename to spec/slither/generator_spec.rb index 0ea0d87..46bb72c 100644 --- a/spec/generator_spec.rb +++ b/spec/slither/generator_spec.rb @@ -1,66 +1,66 @@ -# frozen_string_literal: true - -RSpec.describe Slither::Generator do - subject { described_class.new(definition) } - - let(:definition) do - Slither.define :test do |d| - d.header do |h| - h.trap { |line| line[0,4] == 'HEAD' } - h.column :type, 4 - h.column :file_id, 10 - end - - d.body do |b| - b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ } - b.column :first, 10 - b.column :last, 10 - end - - d.footer do |f| - f.trap { |line| line[0,4] == 'FOOT' } - f.column :type, 4 - f.column :file_id, 10 - end - end - end - - describe ".generate" do - let(:data) do - { - :header => [ {:type => "HEAD", :file_id => "1" }], - :body => [ - {:first => "Paul", :last => "Hewson" }, - {:first => "Dave", :last => "Evans" } - ], - :footer => [ {:type => "FOOT", :file_id => "1" }] - } - end - - it "generate a string" do - expected = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1" - - expect(subject.generate(data)).to eq(expected) - end - - context "when a required section is not present" do - it "raise an error" do - data.delete(:header) - - expect do - subject.generate(data) - end.to raise_error(Slither::RequiredSectionEmptyError) - end - end - - context "when a required section has no content" do - it "raise an error" do - data[:header] = [] - - expect do - subject.generate(data) - end.to raise_error(Slither::RequiredSectionEmptyError) - end - end - end -end +# frozen_string_literal: true + +RSpec.describe Slither::Generator do + subject { described_class.new(definition) } + + let(:definition) do + Slither.define :test do |d| + d.header do |h| + h.trap { |line| line[0,4] == 'HEAD' } + h.column :type, 4 + h.column :file_id, 10 + end + + d.body do |b| + b.trap { |line| line[0,4] =~ /[^(HEAD|FOOT)]/ } + b.column :first, 10 + b.column :last, 10 + end + + d.footer do |f| + f.trap { |line| line[0,4] == 'FOOT' } + f.column :type, 4 + f.column :file_id, 10 + end + end + end + + describe ".generate" do + let(:data) do + { + :header => [ {:type => "HEAD", :file_id => "1" }], + :body => [ + {:first => "Paul", :last => "Hewson" }, + {:first => "Dave", :last => "Evans" } + ], + :footer => [ {:type => "FOOT", :file_id => "1" }] + } + end + + it "generate a string" do + expected = "HEAD 1\n Paul Hewson\n Dave Evans\nFOOT 1" + + expect(subject.generate(data)).to eq(expected) + end + + context "when a required section is not present" do + it "raise an error" do + data.delete(:header) + + expect do + subject.generate(data) + end.to raise_error(Slither::RequiredSectionEmptyError) + end + end + + context "when a required section has no content" do + it "raise an error" do + data[:header] = [] + + expect do + subject.generate(data) + end.to raise_error(Slither::RequiredSectionEmptyError) + end + end + end +end diff --git a/spec/parser_spec.rb b/spec/slither/parser_spec.rb similarity index 100% rename from spec/parser_spec.rb rename to spec/slither/parser_spec.rb diff --git a/spec/section_spec.rb b/spec/slither/section_spec.rb similarity index 96% rename from spec/section_spec.rb rename to spec/slither/section_spec.rb index ab37df7..312be81 100644 --- a/spec/section_spec.rb +++ b/spec/slither/section_spec.rb @@ -1,203 +1,203 @@ -# frozen_string_literal: true - -RSpec.describe Slither::Section do - subject { described_class.new(:body) } - - describe "#initialize" do - it "have no columns after creation" do - expect(subject.columns).to be_empty - end - - it "know its reserved names" do - reserved_names = [:spacer] - - reserved_names.each do |name| - expect(Slither::Section::RESERVED_NAMES).to include(name) - end - end - - context "when specifying the alignment" do - subject { described_class.new(:name, align: alignment) } - - let(:alignment) { :left } - - it "is overriden" do - expect(subject.options[:align]).to eq(alignment) - end - end - end - - describe "#column" do - it "prevent duplicate column names" do - subject.column(:id, 10) - - expect do - subject.column(:id, 10) - end.to raise_error(Slither::DuplicateColumnNameError) - end - - it "should allow duplicate column names that are reserved (i.e. spacer)" do - subject.spacer(10) - - expect do - subject.spacer(10) - subject.spacer(5) - end.not_to raise_error - end - - context "when building many columns" do - it "build an ordered column list" do - columns = [ - subject.column(:id, 10), - subject.column(:name, 30), - subject.column(:state, 2) - ] - - expect(subject.columns).to match(columns) - end - end - - context "when using a method that's not defined" do - it "uses method_missing to create a column" do - column = subject.first_name(5) - - expect(subject.columns).to match([column]) - end - end - end - - describe "#spacer" do - it "create spacer columns" do - spacer_column = subject.spacer(5) - - expect(subject.columns).to match([spacer_column]) - end - end - - describe "#trap" do - context "when trap is a block" do - it "accept and store the trap" do - subject.trap { |v| v == 4 } - - trap = subject.instance_variable_get(:@trap) - - expect(trap).to be_a(Proc) - expect(trap.call(4)).to eq(true) - end - end - - it "should try to match a line using the trap" do - subject.trap { |line| line == "hello" } - - expect(subject.match("hello")).to eq(true) - expect(subject.match("goodbye")).to eq(false) - end - end - - describe "#template" do - before do - subject.definition = Slither::Definition.new - end - - context "when template does not exist" do - it "raise an error if the template is not found on the definition" do - expect do - subject.template(:none).to raise_error(ArgumentError) - end - end - end - - context "when template does exist" do - subject { described_class.new(:body, align: subject_alignment) } - - let(:subject_alignment) { :left } - - before do - subject.definition.template(:test, align: :right) do |template| - template.column(:first, 10) - end - end - - it "add the template columns to the current column list" do - subject.template(:test) - - expect(subject.columns.size).to eq(1) - end - - it "merge the template options with the ones on the section" do - expect(subject.definition.options[:align]).to eq(:right) - - subject.template(:test) - - expect(subject.definition.options[:align]).to eq(:right) - expect(subject.options[:align]).to eq(subject_alignment) - end - end - end - - describe "#format" do - let(:data) { { id: 3, name: "Ryan"} } - - it "transform the 'data' hash to the expected format based on the columns width" do - subject.column(:id, 5) - subject.column(:name, 10) - - data_hash_content_with_15_width = " 3 Ryan" - - expect(subject.format(data)).to eq(data_hash_content_with_15_width) - end - - context "when a column is aligned left" do - it "format and aligns the expected columns to the left" do - subject.column(:id, 5) - subject.column(:name, 10, align: :left) - - data_hash_content_with_15_width_left_aligned = " 3Ryan " - expect(subject.format(data)).to eq(data_hash_content_with_15_width_left_aligned) - end - end - - # TODO: legacy test that has been commented by some reason - # it "should raise an error if the data and column definitions aren't the same size" do - # @section.column(:id, 5) - # lambda { @section.format(@data) }.should raise_error( - # Slither::ColumnMismatchError, - # "The 'body' section has 1 column(s) defined, but there are 2 column(s) provided in the data." - # ) - # end - end - - describe "#parse" do - let(:line) { " 45 Ryan WoodSC " } - let(:columns) do - { id: 5, first: 10, last: 10, state: 2 } - end - let(:expected_result) do - { id: "45", first: "Ryan", last: "Wood", state: "SC" } - end - - before do - columns.each do |key, value| - subject.column(key, value) - end - end - - it "parse the line" do - expect(subject.parse(line)).to eq(expected_result) - end - - context "when section have a column with a reserved name" do - before do - subject.spacer(5) - end - - it "do not return a key for reserved names" do - expect(subject.columns.size).to eq(5) - - expect(subject.parse(line)).to eq(expected_result) - end - end - end - - -end +# frozen_string_literal: true + +RSpec.describe Slither::Section do + subject { described_class.new(:body) } + + describe "#initialize" do + it "have no columns after creation" do + expect(subject.columns).to be_empty + end + + it "know its reserved names" do + reserved_names = [:spacer] + + reserved_names.each do |name| + expect(Slither::Section::RESERVED_NAMES).to include(name) + end + end + + context "when specifying the alignment" do + subject { described_class.new(:name, align: alignment) } + + let(:alignment) { :left } + + it "is overriden" do + expect(subject.options[:align]).to eq(alignment) + end + end + end + + describe "#column" do + it "prevent duplicate column names" do + subject.column(:id, 10) + + expect do + subject.column(:id, 10) + end.to raise_error(Slither::DuplicateColumnNameError) + end + + it "should allow duplicate column names that are reserved (i.e. spacer)" do + subject.spacer(10) + + expect do + subject.spacer(10) + subject.spacer(5) + end.not_to raise_error + end + + context "when building many columns" do + it "build an ordered column list" do + columns = [ + subject.column(:id, 10), + subject.column(:name, 30), + subject.column(:state, 2) + ] + + expect(subject.columns).to match(columns) + end + end + + context "when using a method that's not defined" do + it "uses method_missing to create a column" do + column = subject.first_name(5) + + expect(subject.columns).to match([column]) + end + end + end + + describe "#spacer" do + it "create spacer columns" do + spacer_column = subject.spacer(5) + + expect(subject.columns).to match([spacer_column]) + end + end + + describe "#trap" do + context "when trap is a block" do + it "accept and store the trap" do + subject.trap { |v| v == 4 } + + trap = subject.instance_variable_get(:@trap) + + expect(trap).to be_a(Proc) + expect(trap.call(4)).to eq(true) + end + end + + it "should try to match a line using the trap" do + subject.trap { |line| line == "hello" } + + expect(subject.match("hello")).to eq(true) + expect(subject.match("goodbye")).to eq(false) + end + end + + describe "#template" do + before do + subject.definition = Slither::Definition.new + end + + context "when template does not exist" do + it "raise an error if the template is not found on the definition" do + expect do + subject.template(:none).to raise_error(ArgumentError) + end + end + end + + context "when template does exist" do + subject { described_class.new(:body, align: subject_alignment) } + + let(:subject_alignment) { :left } + + before do + subject.definition.template(:test, align: :right) do |template| + template.column(:first, 10) + end + end + + it "add the template columns to the current column list" do + subject.template(:test) + + expect(subject.columns.size).to eq(1) + end + + it "merge the template options with the ones on the section" do + expect(subject.definition.options[:align]).to eq(:right) + + subject.template(:test) + + expect(subject.definition.options[:align]).to eq(:right) + expect(subject.options[:align]).to eq(subject_alignment) + end + end + end + + describe "#format" do + let(:data) { { id: 3, name: "Ryan"} } + + it "transform the 'data' hash to the expected format based on the columns width" do + subject.column(:id, 5) + subject.column(:name, 10) + + data_hash_content_with_15_width = " 3 Ryan" + + expect(subject.format(data)).to eq(data_hash_content_with_15_width) + end + + context "when a column is aligned left" do + it "format and aligns the expected columns to the left" do + subject.column(:id, 5) + subject.column(:name, 10, align: :left) + + data_hash_content_with_15_width_left_aligned = " 3Ryan " + expect(subject.format(data)).to eq(data_hash_content_with_15_width_left_aligned) + end + end + + # TODO: legacy test that has been commented by some reason + # it "should raise an error if the data and column definitions aren't the same size" do + # @section.column(:id, 5) + # lambda { @section.format(@data) }.should raise_error( + # Slither::ColumnMismatchError, + # "The 'body' section has 1 column(s) defined, but there are 2 column(s) provided in the data." + # ) + # end + end + + describe "#parse" do + let(:line) { " 45 Ryan WoodSC " } + let(:columns) do + { id: 5, first: 10, last: 10, state: 2 } + end + let(:expected_result) do + { id: "45", first: "Ryan", last: "Wood", state: "SC" } + end + + before do + columns.each do |key, value| + subject.column(key, value) + end + end + + it "parse the line" do + expect(subject.parse(line)).to eq(expected_result) + end + + context "when section have a column with a reserved name" do + before do + subject.spacer(5) + end + + it "do not return a key for reserved names" do + expect(subject.columns.size).to eq(5) + + expect(subject.parse(line)).to eq(expected_result) + end + end + end + + +end diff --git a/spec/slither_spec.rb b/spec/slither_spec.rb index c9da382..3d82d8a 100644 --- a/spec/slither_spec.rb +++ b/spec/slither_spec.rb @@ -1,98 +1,98 @@ -# frozen_string_literal: true - -RSpec.describe Slither do - subject { described_class } - - let(:name) { :doc } - let(:options) { { align: :left } } - - describe ".define" do - it "creates a new definition using the specified name and options" do - definition = double("definition") - - expect(subject).to receive(:define).with(name, options).and_return(definition) - - subject.define(name, options) - end - - it "pass the definition to the block" do - yielded = nil - - described_class.define(name) do |y| - yielded = y - end - - expect(yielded).to be_a(Slither::Definition) - end - - it "adds the definition to the internal definition count" do - expect do - subject.define("new_definition", options) {} - end.to change { subject.send(:definitions).count }.by(1) - end - end - - describe ".generate" do - it "should raise an error if the definition name is not found" do - expect do - subject.generate(:not_found_definition, {}) - end.to raise_error(ArgumentError) - end - - it "should output a string" do - simple_definition - - expect( - subject.generate(:simple, simple_definition_test_data) - ).to be_a(String) - end - end - - describe ".write" do - let(:file_name) { "file.txt" } - - it "write a file" do - simple_definition - - file = double("file") - allow(File).to receive(:open).with(file_name, "w").and_yield(file) - expect(file).to receive(:write) - - subject.write(file_name, :simple, simple_definition_test_data) - end - end - - describe ".parse" do - let(:file_name) { "file.txt" } - - it "raise and error if the file does not exists" do - expect do - subject.parse(file_name, :test, {}) - end.to raise_error(ArgumentError) - end - - context "when the file is found" do - before do - allow(File).to receive(:exists?).and_return(true) - end - - context "and the definition is not found" do - it "raises an error due to the definition name not being found" do - expect do - subject.parse(file_name, :test, {}) - end.to raise_error(ArgumentError) - end - end - - context "and the definition is found" do - it "parse the file" do - simple_definition - - expect( - Slither.parse(simple_definition_file, :simple) - ).to eq(simple_definition_test_data) - end - end - end - end -end +# frozen_string_literal: true + +RSpec.describe Slither do + subject { described_class } + + let(:name) { :doc } + let(:options) { { align: :left } } + + describe ".define" do + it "creates a new definition using the specified name and options" do + definition = double("definition") + + expect(subject).to receive(:define).with(name, options).and_return(definition) + + subject.define(name, options) + end + + it "pass the definition to the block" do + yielded = nil + + described_class.define(name) do |y| + yielded = y + end + + expect(yielded).to be_a(Slither::Definition) + end + + it "adds the definition to the internal definition count" do + expect do + subject.define("new_definition", options) {} + end.to change { subject.send(:definitions).count }.by(1) + end + end + + describe ".generate" do + it "should raise an error if the definition name is not found" do + expect do + subject.generate(:not_found_definition, {}) + end.to raise_error(ArgumentError) + end + + it "should output a string" do + simple_definition + + expect( + subject.generate(:simple, simple_definition_test_data) + ).to be_a(String) + end + end + + describe ".write" do + let(:file_name) { "file.txt" } + + it "write a file" do + simple_definition + + file = double("file") + allow(File).to receive(:open).with(file_name, "w").and_yield(file) + expect(file).to receive(:write) + + subject.write(file_name, :simple, simple_definition_test_data) + end + end + + describe ".parse" do + let(:file_name) { "file.txt" } + + it "raise and error if the file does not exists" do + expect do + subject.parse(file_name, :test, {}) + end.to raise_error(ArgumentError) + end + + context "when the file is found" do + before do + allow(File).to receive(:exists?).and_return(true) + end + + context "and the definition is not found" do + it "raises an error due to the definition name not being found" do + expect do + subject.parse(file_name, :test, {}) + end.to raise_error(ArgumentError) + end + end + + context "and the definition is found" do + it "parse the file" do + simple_definition + + expect( + Slither.parse(simple_definition_file, :simple) + ).to eq(simple_definition_test_data) + end + end + end + end +end