From 0925819577355a35abe71a603ff5df532a8f90c7 Mon Sep 17 00:00:00 2001 From: Kristina Spurgin Date: Tue, 10 Dec 2024 18:59:35 -0500 Subject: [PATCH] noblame: standardrb autofix --- csvlint.gemspec | 82 ++++----- lib/csvlint.rb | 34 ++-- spec/validator_spec.rb | 396 ++++++++++++++++++++--------------------- util/csv_testing.rb | 47 ++--- 4 files changed, 280 insertions(+), 279 deletions(-) diff --git a/csvlint.gemspec b/csvlint.gemspec index e3cd71c..d947e0d 100644 --- a/csvlint.gemspec +++ b/csvlint.gemspec @@ -1,52 +1,52 @@ -lib = File.expand_path('lib', __dir__) +lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'csvlint/version' +require "csvlint/version" Gem::Specification.new do |spec| - spec.name = 'csvlint' + spec.name = "csvlint" spec.version = Csvlint::VERSION - spec.authors = ['pezholio'] - spec.email = ['pezholio@gmail.com'] - spec.description = 'CSV Validator' - spec.summary = 'CSV Validator' - spec.homepage = 'https://github.com/theodi/csvlint.rb' - spec.license = 'MIT' + spec.authors = ["pezholio"] + spec.email = ["pezholio@gmail.com"] + spec.description = "CSV Validator" + spec.summary = "CSV Validator" + spec.homepage = "https://github.com/theodi/csvlint.rb" + spec.license = "MIT" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.require_paths = ['lib'] + spec.require_paths = ["lib"] - spec.required_ruby_version = ['>= 2.5', '< 3.4'] + spec.required_ruby_version = [">= 2.5", "< 3.4"] - spec.add_dependency 'activesupport' - spec.add_dependency 'addressable' - spec.add_dependency 'csv' - spec.add_dependency 'escape_utils' - spec.add_dependency 'net-http-persistent' - spec.add_dependency 'open_uri_redirections' - spec.add_dependency 'rack' - spec.add_dependency 'rainbow' - spec.add_dependency 'thor' - spec.add_dependency 'typhoeus' - spec.add_dependency 'uri_template' + spec.add_dependency "activesupport" + spec.add_dependency "addressable" + spec.add_dependency "csv" + spec.add_dependency "escape_utils" + spec.add_dependency "net-http-persistent" + spec.add_dependency "open_uri_redirections" + spec.add_dependency "rack" + spec.add_dependency "rainbow" + spec.add_dependency "thor" + spec.add_dependency "typhoeus" + spec.add_dependency "uri_template" - spec.add_development_dependency 'appraisal' - spec.add_development_dependency 'aruba' - spec.add_development_dependency 'bundler', '>= 1.3' - spec.add_development_dependency 'byebug' - spec.add_development_dependency 'coveralls' - spec.add_development_dependency 'cucumber' - spec.add_development_dependency 'github_changelog_generator' - spec.add_development_dependency 'henry' - spec.add_development_dependency 'rake' - spec.add_development_dependency 'rdf', '< 4.0' - spec.add_development_dependency 'rdf-turtle' - spec.add_development_dependency 'rspec' - spec.add_development_dependency 'rspec-expectations' - spec.add_development_dependency 'rspec-pride' - spec.add_development_dependency 'simplecov' - spec.add_development_dependency 'simplecov-rcov' - spec.add_development_dependency 'spork' - spec.add_development_dependency 'standardrb' - spec.add_development_dependency 'webmock' + spec.add_development_dependency "appraisal" + spec.add_development_dependency "aruba" + spec.add_development_dependency "bundler", ">= 1.3" + spec.add_development_dependency "byebug" + spec.add_development_dependency "coveralls" + spec.add_development_dependency "cucumber" + spec.add_development_dependency "github_changelog_generator" + spec.add_development_dependency "henry" + spec.add_development_dependency "rake" + spec.add_development_dependency "rdf", "< 4.0" + spec.add_development_dependency "rdf-turtle" + spec.add_development_dependency "rspec" + spec.add_development_dependency "rspec-expectations" + spec.add_development_dependency "rspec-pride" + spec.add_development_dependency "simplecov" + spec.add_development_dependency "simplecov-rcov" + spec.add_development_dependency "spork" + spec.add_development_dependency "standardrb" + spec.add_development_dependency "webmock" end diff --git a/lib/csvlint.rb b/lib/csvlint.rb index 8e33651..45871dd 100644 --- a/lib/csvlint.rb +++ b/lib/csvlint.rb @@ -1,24 +1,24 @@ -require 'csv' -require 'date' -require 'open-uri' -require 'tempfile' -require 'typhoeus' +require "csv" +require "date" +require "open-uri" +require "tempfile" +require "typhoeus" require "active_support/all" require "open_uri_redirections" require "uri_template" -require 'csvlint/error_message' -require 'csvlint/error_collector' -require 'csvlint/validate' -require 'csvlint/field' +require "csvlint/error_message" +require "csvlint/error_collector" +require "csvlint/validate" +require "csvlint/field" -require 'csvlint/csvw/metadata_error' -require 'csvlint/csvw/number_format' -require 'csvlint/csvw/date_format' -require 'csvlint/csvw/property_checker' -require 'csvlint/csvw/column' -require 'csvlint/csvw/table' -require 'csvlint/csvw/table_group' +require "csvlint/csvw/metadata_error" +require "csvlint/csvw/number_format" +require "csvlint/csvw/date_format" +require "csvlint/csvw/property_checker" +require "csvlint/csvw/column" +require "csvlint/csvw/table" +require "csvlint/csvw/table_group" -require 'csvlint/schema' +require "csvlint/schema" diff --git a/spec/validator_spec.rb b/spec/validator_spec.rb index c6e5345..06c3380 100644 --- a/spec/validator_spec.rb +++ b/spec/validator_spec.rb @@ -1,17 +1,17 @@ -require 'spec_helper' +require "spec_helper" describe Csvlint::Validator do before do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, body: '') - stub_request(:get, 'http://example.com/.well-known/csvm').to_return(status: 404) - stub_request(:get, 'http://example.com/example.csv-metadata.json').to_return(status: 404) - stub_request(:get, 'http://example.com/csv-metadata.json').to_return(status: 404) + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, body: "") + stub_request(:get, "http://example.com/.well-known/csvm").to_return(status: 404) + stub_request(:get, "http://example.com/example.csv-metadata.json").to_return(status: 404) + stub_request(:get, "http://example.com/csv-metadata.json").to_return(status: 404) end - it 'should validate from a URL' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should validate from a URL" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.valid?).to eql(true) expect(validator.instance_variable_get(:@expected_columns)).to eql(3) @@ -19,9 +19,9 @@ expect(validator.data.size).to eql(3) end - it 'should validate from a file path' do - validator = Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', - 'valid.csv'))) + it "should validate from a file path" do + validator = Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), "..", "features", "fixtures", + "valid.csv"))) expect(validator.valid?).to eql(true) expect(validator.instance_variable_get(:@expected_columns)).to eql(3) @@ -29,27 +29,27 @@ expect(validator.data.size).to eql(3) end - it 'should validate from a file path including whitespace' do - validator = Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', - 'white space in filename.csv'))) + it "should validate from a file path including whitespace" do + validator = Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), "..", "features", "fixtures", + "white space in filename.csv"))) expect(validator.valid?).to eql(true) end - context 'multi line CSV validation with included schema' do + context "multi line CSV validation with included schema" do end - context 'single line row validation with included schema' do + context "single line row validation with included schema" do end - context 'validation with multiple lines: ' do + context "validation with multiple lines: " do # TODO: multiple lines permits testing of warnings # TODO need more assertions in each test IE @formats # TODO the phrasing of col_counts if only consulting specs might be confusing # TODO ^-> col_counts and data.size should be equivalent, but only data is populated outside of if row.nil? # TODO ^- -> and its less the size of col_counts than the homogeneity of its contents which is important - it '.each() -> parse_contents method validates a well formed CSV' do + it ".each() -> parse_contents method validates a well formed CSV" do # when invoking parse contents data = StringIO.new(%("Foo","Bar","Baz"\r\n"1","2","3"\r\n"1","2","3"\r\n"3","2","1")) @@ -63,7 +63,7 @@ expect(validator.data.size).to eql(4) end - it '.each() -> `parse_contents` parses malformed CSV and catches unclosed quote' do + it ".each() -> `parse_contents` parses malformed CSV and catches unclosed quote" do # doesn't build warnings because check_consistency isn't invoked data = StringIO.new(%("Foo","Bar","Baz"\r\n"1","2","3"\r\n"1","2","3"\r\n"3","2","1)) @@ -74,7 +74,7 @@ expect(validator.errors.first.type).to eql(:unclosed_quote) end - it '.each() -> `parse_contents` parses malformed CSV and catches whitespace and edge case' do + it ".each() -> `parse_contents` parses malformed CSV and catches whitespace and edge case" do # when this data gets passed the header it rescues a whitespace error, resulting in the header row being discarded # TODO - check if this is an edge case, currently passing because it requires advice on how to specify data = StringIO.new(%( "Foo","Bar","Baz"\r\n"1","2","3"\r\n"1","2","3"\r\n"3","2","1" )) @@ -86,47 +86,47 @@ expect(validator.errors.count).to eql(2) end - it 'handles line breaks within a cell' do + it "handles line breaks within a cell" do data = StringIO.new(%("a","b","c"\r\n"d","e","this is\r\nvalid"\r\n"a","b","c")) validator = Csvlint::Validator.new(data) expect(validator.valid?).to eql(true) end - it 'handles multiple line breaks within a cell' do + it "handles multiple line breaks within a cell" do data = StringIO.new(%("a","b","c"\r\n"d","this is\r\n valid","as is this\r\n too")) validator = Csvlint::Validator.new(data) expect(validator.valid?).to eql(true) end end - context 'csv dialect' do - it 'should provide sensible defaults for CSV parsing' do - validator = Csvlint::Validator.new('http://example.com/example.csv') + context "csv dialect" do + it "should provide sensible defaults for CSV parsing" do + validator = Csvlint::Validator.new("http://example.com/example.csv") opts = validator.instance_variable_get(:@csv_options) expect(opts).to include({ - col_sep: ',', - row_sep: :auto, - quote_char: '"', - skip_blanks: false - }) + col_sep: ",", + row_sep: :auto, + quote_char: '"', + skip_blanks: false + }) end - it 'should map CSV DDF to correct values' do - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should map CSV DDF to correct values" do + validator = Csvlint::Validator.new("http://example.com/example.csv") opts = validator.dialect_to_csv_options({ - 'lineTerminator' => "\n", - 'delimiter' => "\t", - 'quoteChar' => "'" - }) + "lineTerminator" => "\n", + "delimiter" => "\t", + "quoteChar" => "'" + }) expect(opts).to include({ - col_sep: "\t", - row_sep: "\n", - quote_char: "'", - skip_blanks: false - }) + col_sep: "\t", + row_sep: "\n", + quote_char: "'", + skip_blanks: false + }) end - it '.each() -> `validate` to pass input in streaming fashion' do + it ".each() -> `validate` to pass input in streaming fashion" do # warnings are built when validate is used to call all three methods data = StringIO.new(%("Foo","Bar","Baz"\r\n"1","2","3"\r\n"1","2","3"\r\n"3","2","1")) validator = Csvlint::Validator.new(data) @@ -138,7 +138,7 @@ expect(validator.info_messages.count).to eql(1) end - it '.each() -> `validate` parses malformed CSV, populates errors, warnings & info_msgs,invokes finish()' do + it ".each() -> `validate` parses malformed CSV, populates errors, warnings & info_msgs,invokes finish()" do data = StringIO.new(%("Foo","Bar","Baz"\r\n"1","2","3"\r\n"1","2","3"\r\n"1","two","3"\r\n"3","2", "1")) validator = Csvlint::Validator.new(data) @@ -154,9 +154,9 @@ expect(validator.warnings.first.type).to eql(:inconsistent_values) end - it 'File.open.each_line -> `validate` passes a valid csv' do - filename = 'valid_many_rows.csv' - file = File.join(File.expand_path(Dir.pwd), 'features', 'fixtures', filename) + it "File.open.each_line -> `validate` passes a valid csv" do + filename = "valid_many_rows.csv" + file = File.join(File.expand_path(Dir.pwd), "features", "fixtures", filename) validator = Csvlint::Validator.new(File.new(file)) expect(validator.valid?).to eql(true) @@ -166,37 +166,37 @@ end end - context 'with a single row' do - it 'validates correctly' do + context "with a single row" do + it "validates correctly" do stream = "\"a\",\"b\",\"c\"\r\n" - validator = Csvlint::Validator.new(StringIO.new(stream), 'header' => false) + validator = Csvlint::Validator.new(StringIO.new(stream), "header" => false) expect(validator.valid?).to eql(true) end - it 'checks for non rfc line breaks' do + it "checks for non rfc line breaks" do stream = "\"a\",\"b\",\"c\"\n" - validator = Csvlint::Validator.new(StringIO.new(stream), { 'header' => false }) + validator = Csvlint::Validator.new(StringIO.new(stream), {"header" => false}) expect(validator.valid?).to eql(true) expect(validator.info_messages.count).to eq(1) expect(validator.info_messages.first.type).to eql(:nonrfc_line_breaks) end - it 'checks for blank rows' do + it "checks for blank rows" do data = StringIO.new('"","",') - validator = Csvlint::Validator.new(data, 'header' => false) + validator = Csvlint::Validator.new(data, "header" => false) expect(validator.valid?).to eql(false) expect(validator.errors.count).to eq(1) expect(validator.errors.first.type).to eql(:blank_rows) end - it 'returns the content of the string with the error' do + it "returns the content of the string with the error" do stream = "\"\",\"\",\"\"\r\n" - validator = Csvlint::Validator.new(StringIO.new(stream), 'header' => false) + validator = Csvlint::Validator.new(StringIO.new(stream), "header" => false) expect(validator.errors.first.content).to eql("\"\",\"\",\"\"\r\n") end - it 'should presume a header unless told otherwise' do + it "should presume a header unless told otherwise" do stream = "1,2,3\r\n" validator = Csvlint::Validator.new(StringIO.new(stream)) @@ -208,15 +208,15 @@ it "should evaluate the row as 'row 2' when stipulated" do stream = "1,2,3\r\n" - validator = Csvlint::Validator.new(StringIO.new(stream), 'header' => false) + validator = Csvlint::Validator.new(StringIO.new(stream), "header" => false) validator.validate expect(validator.valid?).to eql(true) expect(validator.info_messages.size).to eql(0) end end - context 'it returns the correct error from ERROR_MATCHES' do - it 'checks for unclosed quotes' do + context "it returns the correct error from ERROR_MATCHES" do + it "checks for unclosed quotes" do stream = "\"a,\"b\",\"c\"\n" validator = Csvlint::Validator.new(StringIO.new(stream)) expect(validator.valid?).to eql(false) @@ -234,7 +234,7 @@ # expect(validator.errors.first.type).to eql(:stray_quote) # end - it 'checks for whitespace' do + it "checks for whitespace" do stream = " \"a\",\"b\",\"c\"\r\n" validator = Csvlint::Validator.new(StringIO.new(stream)) @@ -243,19 +243,19 @@ expect(validator.errors.first.type).to eql(:whitespace) end - it 'returns line break errors if incorrectly specified' do + it "returns line break errors if incorrectly specified" do # TODO: the logic for catching this error message is very esoteric stream = "\"a\",\"b\",\"c\"\n" - validator = Csvlint::Validator.new(StringIO.new(stream), { 'lineTerminator' => "\r\n" }) + validator = Csvlint::Validator.new(StringIO.new(stream), {"lineTerminator" => "\r\n"}) expect(validator.valid?).to eql(false) expect(validator.errors.count).to eq(1) expect(validator.errors.first.type).to eql(:line_breaks) end end - context 'when validating headers' do + context "when validating headers" do it "should warn if column names aren't unique" do - data = StringIO.new('minimum, minimum') + data = StringIO.new("minimum, minimum") validator = Csvlint::Validator.new(data) validator.reset expect(validator.validate_header(%w[minimum minimum])).to eql(true) @@ -264,17 +264,17 @@ expect(validator.warnings.first.category).to eql(:schema) end - it 'should warn if column names are blank' do - data = StringIO.new('minimum,') + it "should warn if column names are blank" do + data = StringIO.new("minimum,") validator = Csvlint::Validator.new(data) - expect(validator.validate_header(['minimum', ''])).to eql(true) + expect(validator.validate_header(["minimum", ""])).to eql(true) expect(validator.warnings.size).to eql(1) expect(validator.warnings.first.type).to eql(:empty_column_name) expect(validator.warnings.first.category).to eql(:schema) end - it 'should include info message about missing header when we have assumed a header' do + it "should include info message about missing header when we have assumed a header" do data = StringIO.new("1,2,3\r\n") validator = Csvlint::Validator.new(data) expect(validator.valid?).to eql(true) @@ -283,27 +283,27 @@ expect(validator.info_messages.first.category).to eql(:structure) end - it 'should not include info message about missing header when we are told about the header' do + it "should not include info message about missing header when we are told about the header" do data = StringIO.new("1,2,3\r\n") - validator = Csvlint::Validator.new(data, 'header' => false) + validator = Csvlint::Validator.new(data, "header" => false) expect(validator.valid?).to eql(true) expect(validator.info_messages.size).to eql(0) end end - context 'build_formats' do + context "build_formats" do { - string: 'foo', - numeric: '1', - uri: 'http://www.example.com', - dateTime_iso8601: '2013-01-01T13:00:00Z', - date_db: '2013-01-01', - dateTime_hms: '13:00:00' + string: "foo", + numeric: "1", + uri: "http://www.example.com", + dateTime_iso8601: "2013-01-01T13:00:00Z", + date_db: "2013-01-01", + dateTime_hms: "13:00:00" }.each do |type, content| it "should return the format of #{type} correctly" do row = [content] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") validator.build_formats(row) formats = validator.instance_variable_get(:@formats) @@ -311,10 +311,10 @@ end end - it 'treats floats and ints the same' do - row = ['12', '3.1476'] + it "treats floats and ints the same" do + row = ["12", "3.1476"] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") validator.build_formats(row) formats = validator.instance_variable_get(:@formats) @@ -322,40 +322,40 @@ expect(formats[1].keys.first).to eql :numeric end - it 'should ignore blank arrays' do + it "should ignore blank arrays" do row = [] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") validator.build_formats(row) formats = validator.instance_variable_get(:@formats) expect(formats).to eql [] end - it 'should work correctly for single columns' do + it "should work correctly for single columns" do rows = [ - ['foo'], - ['bar'], - ['baz'] + ["foo"], + ["bar"], + ["baz"] ] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") rows.each_with_index do |row, _i| validator.build_formats(row) end formats = validator.instance_variable_get(:@formats) - expect(formats).to eql [{ string: 3 }] + expect(formats).to eql [{string: 3}] end - it 'should return formats correctly if a row is blank' do + it "should return formats correctly if a row is blank" do rows = [ [], - ['foo', '1', '$2345'] + ["foo", "1", "$2345"] ] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") rows.each_with_index do |row, _i| validator.build_formats(row) @@ -364,50 +364,50 @@ formats = validator.instance_variable_get(:@formats) expect(formats).to eql [ - { string: 1 }, - { numeric: 1 }, - { string: 1 } + {string: 1}, + {numeric: 1}, + {string: 1} ] end end - context 'csv dialect' do - it 'should provide sensible defaults for CSV parsing' do - validator = Csvlint::Validator.new('http://example.com/example.csv') + context "csv dialect" do + it "should provide sensible defaults for CSV parsing" do + validator = Csvlint::Validator.new("http://example.com/example.csv") opts = validator.instance_variable_get(:@csv_options) expect(opts).to include({ - col_sep: ',', - row_sep: :auto, - quote_char: '"', - skip_blanks: false - }) + col_sep: ",", + row_sep: :auto, + quote_char: '"', + skip_blanks: false + }) end - it 'should map CSV DDF to correct values' do - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should map CSV DDF to correct values" do + validator = Csvlint::Validator.new("http://example.com/example.csv") opts = validator.dialect_to_csv_options({ - 'lineTerminator' => "\n", - 'delimiter' => "\t", - 'quoteChar' => "'" - }) + "lineTerminator" => "\n", + "delimiter" => "\t", + "quoteChar" => "'" + }) expect(opts).to include({ - col_sep: "\t", - row_sep: "\n", - quote_char: "'", - skip_blanks: false - }) + col_sep: "\t", + row_sep: "\n", + quote_char: "'", + skip_blanks: false + }) end end - context 'check_consistency' do - it 'should return a warning if columns have inconsistent values' do + context "check_consistency" do + it "should return a warning if columns have inconsistent values" do formats = [ - { string: 3 }, - { string: 2, numeric: 1 }, - { numeric: 3 } + {string: 3}, + {string: 2, numeric: 1}, + {numeric: 3} ] - validator = Csvlint::Validator.new('http://example.com/example.csv') + validator = Csvlint::Validator.new("http://example.com/example.csv") validator.instance_variable_set(:@formats, formats) validator.check_consistency @@ -419,81 +419,81 @@ end # TODO: the below tests are all the remaining tests from validator_spec.rb, annotations indicate their status HOWEVER these tests may be best refactored into client specs - context 'when detecting headers' do - it 'should default to expecting a header' do - validator = Csvlint::Validator.new('http://example.com/example.csv') + context "when detecting headers" do + it "should default to expecting a header" do + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.header?).to eql(true) end - it 'should look in CSV options to detect header' do + it "should look in CSV options to detect header" do opts = { - 'header' => true + "header" => true } - validator = Csvlint::Validator.new('http://example.com/example.csv', opts) + validator = Csvlint::Validator.new("http://example.com/example.csv", opts) expect(validator.header?).to eql(true) opts = { - 'header' => false + "header" => false } - validator = Csvlint::Validator.new('http://example.com/example.csv', opts) + validator = Csvlint::Validator.new("http://example.com/example.csv", opts) expect(validator.header?).to eql(false) end - it 'should look in content-type for header=absent' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv; header=absent' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should look in content-type for header=absent" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv; header=absent"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.header?).to eql(false) expect(validator.errors.size).to eql(0) end - it 'should look in content-type for header=present' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv; header=present' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should look in content-type for header=present" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv; header=present"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.header?).to eql(true) expect(validator.errors.size).to eql(0) end - it 'assume header present if not specified in content type' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "assume header present if not specified in content type" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.header?).to eql(true) expect(validator.errors.size).to eql(0) expect(validator.info_messages.size).to eql(1) expect(validator.info_messages.first.type).to eql(:assumed_header) end - it 'give wrong content type error if content type is wrong' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/html' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "give wrong content type error if content type is wrong" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/html"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.header?).to eql(true) expect(validator.errors.size).to eql(1) expect(validator.errors[0].type).to eql(:wrong_content_type) end end - context 'when validating headers' do + context "when validating headers" do it "should warn if column names aren't unique" do - data = StringIO.new('minimum, minimum') + data = StringIO.new("minimum, minimum") validator = Csvlint::Validator.new(data) expect(validator.warnings.size).to eql(1) expect(validator.warnings.first.type).to eql(:duplicate_column_name) expect(validator.warnings.first.category).to eql(:schema) end - it 'should warn if column names are blank' do - data = StringIO.new('minimum,') + it "should warn if column names are blank" do + data = StringIO.new("minimum,") validator = Csvlint::Validator.new(data) - expect(validator.validate_header(['minimum', ''])).to eql(true) + expect(validator.validate_header(["minimum", ""])).to eql(true) expect(validator.warnings.size).to eql(1) expect(validator.warnings.first.type).to eql(:empty_column_name) expect(validator.warnings.first.category).to eql(:schema) end - it 'should include info message about missing header when we have assumed a header' do + it "should include info message about missing header when we have assumed a header" do data = StringIO.new("1,2,3\r\n") validator = Csvlint::Validator.new(data) @@ -503,61 +503,61 @@ expect(validator.info_messages.first.category).to eql(:structure) end - it 'should not include info message about missing header when we are told about the header' do + it "should not include info message about missing header when we are told about the header" do data = StringIO.new("1,2,3\r\n") - validator = Csvlint::Validator.new(data, 'header' => false) + validator = Csvlint::Validator.new(data, "header" => false) expect(validator.valid?).to eql(true) expect(validator.info_messages.size).to eql(0) end it "should not be an error if we have assumed a header, there is no dialect and content-type doesn't declare header, as we assume header=present" do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.valid?).to eql(true) end - it 'should be valid if we have a dialect and the data is from the web' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) + it "should be valid if we have a dialect and the data is from the web" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) # header defaults to true in csv dialect, so this is valid - validator = Csvlint::Validator.new('http://example.com/example.csv', {}) + validator = Csvlint::Validator.new("http://example.com/example.csv", {}) expect(validator.valid?).to eql(true) - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv', { 'header' => true }) + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv", {"header" => true}) expect(validator.valid?).to eql(true) - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv' }, body: File.read(File.join(File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv'))) - validator = Csvlint::Validator.new('http://example.com/example.csv', { 'header' => false }) + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv"}, body: File.read(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv"))) + validator = Csvlint::Validator.new("http://example.com/example.csv", {"header" => false}) expect(validator.valid?).to eql(true) end end - context 'accessing metadata' do + context "accessing metadata" do before :all do - stub_request(:get, 'http://example.com/crlf.csv').to_return(status: 200, - body: File.read(File.join( - File.dirname(__FILE__), '..', 'features', 'fixtures', 'windows-line-endings.csv' - ))) - stub_request(:get, 'http://example.com/crlf.csv-metadata.json').to_return(status: 404) + stub_request(:get, "http://example.com/crlf.csv").to_return(status: 200, + body: File.read(File.join( + File.dirname(__FILE__), "..", "features", "fixtures", "windows-line-endings.csv" + ))) + stub_request(:get, "http://example.com/crlf.csv-metadata.json").to_return(status: 404) end - it 'can get line break symbol' do - validator = Csvlint::Validator.new('http://example.com/crlf.csv') + it "can get line break symbol" do + validator = Csvlint::Validator.new("http://example.com/crlf.csv") expect(validator.line_breaks).to eql "\r\n" end end - it 'should give access to the complete CSV data file' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv; header=present' }, - body: File.read(File.join( - File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv' - ))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should give access to the complete CSV data file" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv; header=present"}, + body: File.read(File.join( + File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv" + ))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.valid?).to eql(true) data = validator.data @@ -566,38 +566,38 @@ expect(data[2]).to eql %w[3 2 1] end - it 'should count the total number of rows read' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv; header=present' }, - body: File.read(File.join( - File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv' - ))) - validator = Csvlint::Validator.new('http://example.com/example.csv') + it "should count the total number of rows read" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv; header=present"}, + body: File.read(File.join( + File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv" + ))) + validator = Csvlint::Validator.new("http://example.com/example.csv") expect(validator.row_count).to eq(3) end - it 'should limit number of lines read' do - stub_request(:get, 'http://example.com/example.csv').to_return(status: 200, - headers: { 'Content-Type' => 'text/csv; header=present' }, - body: File.read(File.join( - File.dirname(__FILE__), '..', 'features', 'fixtures', 'valid.csv' - ))) - validator = Csvlint::Validator.new('http://example.com/example.csv', {}, nil, limit_lines: 2) + it "should limit number of lines read" do + stub_request(:get, "http://example.com/example.csv").to_return(status: 200, + headers: {"Content-Type" => "text/csv; header=present"}, + body: File.read(File.join( + File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv" + ))) + validator = Csvlint::Validator.new("http://example.com/example.csv", {}, nil, limit_lines: 2) expect(validator.valid?).to eql(true) data = validator.data expect(data.count).to eql 2 expect(data[0]).to eql %w[Foo Bar Baz] end - context 'with a lambda' do - it 'should call a lambda for each line' do + context "with a lambda" do + it "should call a lambda for each line" do @count = 0 mylambda = lambda { |row| @count += 1 } Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv")), {}, nil, {lambda: mylambda}) expect(@count).to eq(3) end - it 'reports back the status of each line' do + it "reports back the status of each line" do @results = [] mylambda = lambda { |row| @results << row.current_line } Csvlint::Validator.new(File.new(File.join(File.dirname(__FILE__), "..", "features", "fixtures", "valid.csv")), {}, nil, {lambda: mylambda}) diff --git a/util/csv_testing.rb b/util/csv_testing.rb index ffb8727..84828d3 100644 --- a/util/csv_testing.rb +++ b/util/csv_testing.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -require 'bundler/inline' +require "bundler/inline" gemfile(true) do - source 'https://rubygems.org' - gem 'csv' - gem 'csvlint', path: '../' - gem 'pry' + source "https://rubygems.org" + gem "csv" + gem "csvlint", path: "../" + gem "pry" end module Ct @@ -15,9 +15,9 @@ module Ct class Test EOL_MAP = { - "\r" => 'CR', - "\n" => 'LF', - "\r\n" => 'CRLF' + "\r" => "CR", + "\n" => "LF", + "\r\n" => "CRLF" } def initialize(main_eol, test_eol, loc) @@ -28,6 +28,7 @@ def initialize(main_eol, test_eol, loc) end def csv_parse = @csv_parse ||= run_csv_parse + def lint = @lint ||= run_lint def row_count @@ -52,41 +53,41 @@ def result = { def set_csv case loc - when 'final row ending' + when "final row ending" "obj,note#{main_eol}val,val#{main_eol}val,val#{test_eol}" - when 'extra blank row at end' + when "extra blank row at end" "obj,note#{main_eol}val,val#{main_eol}val,val#{main_eol}#{test_eol}" - when 'blank row between populated rows' + when "blank row between populated rows" "obj,note#{main_eol}val,val#{main_eol}#{test_eol}val,val#{main_eol}" end end def run_csv_parse - CSV.parse(csv, headers: true, nil_value: '') - rescue StandardError => e + CSV.parse(csv, headers: true, nil_value: "") + rescue => e "#{e.class}: #{e.message}" else - 'success' + "success" end def run_lint @v = Csvlint::Validator.new(StringIO.new(csv)) - rescue StandardError => e + rescue => e @v = nil "VALIDATION ERROR: #{e}" else - return 'valid' if @v.errors.empty? + return "valid" if @v.errors.empty? - @v.errors.map(&:type).join('; ') + @v.errors.map(&:type).join("; ") end end module_function def base_test_configs(main, test) - ['final row ending', - 'extra blank row at end', - 'blank row between populated rows'].map do |loc| + ["final row ending", + "extra blank row at end", + "blank row between populated rows"].map do |loc| Test.new(main, test, loc) end end @@ -106,12 +107,12 @@ def perms end tr = perms.map { |pair| base_test_configs(*pair) } - .flatten - .map(&:result) + .flatten + .map(&:result) headers = tr[0].keys - CSV.open('csv_testing.csv', 'w', write_headers: true, headers: headers) do |csv| + CSV.open("csv_testing.csv", "w", write_headers: true, headers: headers) do |csv| tr.each do |result| csv << result.values_at(*headers) end