berkeley_library-tind 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/build.yml +18 -0
- data/.gitignore +388 -0
- data/.idea/inspectionProfiles/Project_Default.xml +20 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/tind.iml +138 -0
- data/.idea/vcs.xml +6 -0
- data/.rubocop.yml +334 -0
- data/.ruby-version +1 -0
- data/.simplecov +8 -0
- data/.yardopts +1 -0
- data/CHANGES.md +58 -0
- data/Dockerfile +57 -0
- data/Gemfile +3 -0
- data/Jenkinsfile +18 -0
- data/LICENSE.md +21 -0
- data/README.md +73 -0
- data/Rakefile +20 -0
- data/berkeley_library-tind.gemspec +50 -0
- data/bin/tind-export +14 -0
- data/docker-compose.yml +15 -0
- data/lib/berkeley_library/tind.rb +3 -0
- data/lib/berkeley_library/tind/api.rb +1 -0
- data/lib/berkeley_library/tind/api/api.rb +132 -0
- data/lib/berkeley_library/tind/api/api_exception.rb +131 -0
- data/lib/berkeley_library/tind/api/collection.rb +82 -0
- data/lib/berkeley_library/tind/api/date_range.rb +67 -0
- data/lib/berkeley_library/tind/api/format.rb +32 -0
- data/lib/berkeley_library/tind/api/search.rb +100 -0
- data/lib/berkeley_library/tind/config.rb +103 -0
- data/lib/berkeley_library/tind/export.rb +1 -0
- data/lib/berkeley_library/tind/export/column.rb +54 -0
- data/lib/berkeley_library/tind/export/column_group.rb +144 -0
- data/lib/berkeley_library/tind/export/column_group_list.rb +131 -0
- data/lib/berkeley_library/tind/export/column_width_calculator.rb +76 -0
- data/lib/berkeley_library/tind/export/config.rb +154 -0
- data/lib/berkeley_library/tind/export/csv_exporter.rb +29 -0
- data/lib/berkeley_library/tind/export/export.rb +47 -0
- data/lib/berkeley_library/tind/export/export_command.rb +168 -0
- data/lib/berkeley_library/tind/export/export_exception.rb +8 -0
- data/lib/berkeley_library/tind/export/export_format.rb +67 -0
- data/lib/berkeley_library/tind/export/exporter.rb +105 -0
- data/lib/berkeley_library/tind/export/filter.rb +52 -0
- data/lib/berkeley_library/tind/export/no_results_error.rb +7 -0
- data/lib/berkeley_library/tind/export/ods_exporter.rb +138 -0
- data/lib/berkeley_library/tind/export/row.rb +24 -0
- data/lib/berkeley_library/tind/export/row_metrics.rb +18 -0
- data/lib/berkeley_library/tind/export/table.rb +175 -0
- data/lib/berkeley_library/tind/export/table_metrics.rb +116 -0
- data/lib/berkeley_library/tind/marc.rb +1 -0
- data/lib/berkeley_library/tind/marc/xml_reader.rb +144 -0
- data/lib/berkeley_library/tind/module_info.rb +14 -0
- data/lib/berkeley_library/util/arrays.rb +178 -0
- data/lib/berkeley_library/util/logging.rb +1 -0
- data/lib/berkeley_library/util/ods/spreadsheet.rb +170 -0
- data/lib/berkeley_library/util/ods/xml/content_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/document_node.rb +57 -0
- data/lib/berkeley_library/util/ods/xml/element_node.rb +106 -0
- data/lib/berkeley_library/util/ods/xml/loext/table_protection.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/manifest/file_entry.rb +42 -0
- data/lib/berkeley_library/util/ods/xml/manifest/manifest.rb +73 -0
- data/lib/berkeley_library/util/ods/xml/manifest_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/namespace.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/office/automatic_styles.rb +181 -0
- data/lib/berkeley_library/util/ods/xml/office/body.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/document_content.rb +98 -0
- data/lib/berkeley_library/util/ods/xml/office/document_styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/office/font_face_decls.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/office/scripts.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/spreadsheet.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/office/styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/style/cell_style.rb +58 -0
- data/lib/berkeley_library/util/ods/xml/style/column_style.rb +36 -0
- data/lib/berkeley_library/util/ods/xml/style/default_style.rb +31 -0
- data/lib/berkeley_library/util/ods/xml/style/family.rb +85 -0
- data/lib/berkeley_library/util/ods/xml/style/font_face.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/style/paragraph_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/row_style.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/style/style.rb +44 -0
- data/lib/berkeley_library/util/ods/xml/style/table_cell_properties.rb +40 -0
- data/lib/berkeley_library/util/ods/xml/style/table_column_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/table_properties.rb +25 -0
- data/lib/berkeley_library/util/ods/xml/style/table_row_properties.rb +28 -0
- data/lib/berkeley_library/util/ods/xml/style/table_style.rb +27 -0
- data/lib/berkeley_library/util/ods/xml/style/text_properties.rb +52 -0
- data/lib/berkeley_library/util/ods/xml/styles_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/table/named_expressions.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/table/repeatable.rb +38 -0
- data/lib/berkeley_library/util/ods/xml/table/table.rb +193 -0
- data/lib/berkeley_library/util/ods/xml/table/table_cell.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/table/table_column.rb +43 -0
- data/lib/berkeley_library/util/ods/xml/table/table_row.rb +136 -0
- data/lib/berkeley_library/util/ods/xml/text/p.rb +118 -0
- data/lib/berkeley_library/util/paths.rb +111 -0
- data/lib/berkeley_library/util/stringios.rb +30 -0
- data/lib/berkeley_library/util/strings.rb +42 -0
- data/lib/berkeley_library/util/sys_exits.rb +15 -0
- data/lib/berkeley_library/util/times.rb +22 -0
- data/lib/berkeley_library/util/uris.rb +44 -0
- data/lib/berkeley_library/util/uris/appender.rb +162 -0
- data/lib/berkeley_library/util/uris/requester.rb +62 -0
- data/lib/berkeley_library/util/uris/validator.rb +32 -0
- data/rakelib/bundle.rake +8 -0
- data/rakelib/coverage.rake +11 -0
- data/rakelib/gem.rake +54 -0
- data/rakelib/rubocop.rake +18 -0
- data/rakelib/spec.rake +2 -0
- data/spec/.rubocop.yml +40 -0
- data/spec/berkeley_library/tind/api/api_exception_spec.rb +91 -0
- data/spec/berkeley_library/tind/api/api_spec.rb +143 -0
- data/spec/berkeley_library/tind/api/collection_spec.rb +74 -0
- data/spec/berkeley_library/tind/api/date_range_spec.rb +110 -0
- data/spec/berkeley_library/tind/api/format_spec.rb +54 -0
- data/spec/berkeley_library/tind/api/search_spec.rb +364 -0
- data/spec/berkeley_library/tind/config_spec.rb +86 -0
- data/spec/berkeley_library/tind/export/column_group_spec.rb +29 -0
- data/spec/berkeley_library/tind/export/column_spec.rb +43 -0
- data/spec/berkeley_library/tind/export/config_spec.rb +206 -0
- data/spec/berkeley_library/tind/export/export_command_spec.rb +169 -0
- data/spec/berkeley_library/tind/export/export_format_spec.rb +59 -0
- data/spec/berkeley_library/tind/export/export_matcher.rb +112 -0
- data/spec/berkeley_library/tind/export/export_spec.rb +150 -0
- data/spec/berkeley_library/tind/export/exporter_spec.rb +125 -0
- data/spec/berkeley_library/tind/export/row_spec.rb +118 -0
- data/spec/berkeley_library/tind/export/table_spec.rb +322 -0
- data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +93 -0
- data/spec/berkeley_library/util/arrays_spec.rb +340 -0
- data/spec/berkeley_library/util/ods/spreadsheet_spec.rb +124 -0
- data/spec/berkeley_library/util/ods/xml/content_doc_spec.rb +121 -0
- data/spec/berkeley_library/util/ods/xml/manifest/file_entry_spec.rb +27 -0
- data/spec/berkeley_library/util/ods/xml/manifest/manifest_spec.rb +33 -0
- data/spec/berkeley_library/util/ods/xml/office/document_content_spec.rb +60 -0
- data/spec/berkeley_library/util/ods/xml/style/automatic_styles_spec.rb +37 -0
- data/spec/berkeley_library/util/ods/xml/style/family_spec.rb +57 -0
- data/spec/berkeley_library/util/ods/xml/table/table_row_spec.rb +179 -0
- data/spec/berkeley_library/util/ods/xml/table/table_spec.rb +218 -0
- data/spec/berkeley_library/util/paths_spec.rb +90 -0
- data/spec/berkeley_library/util/stringios_spec.rb +34 -0
- data/spec/berkeley_library/util/strings_spec.rb +27 -0
- data/spec/berkeley_library/util/times_spec.rb +39 -0
- data/spec/berkeley_library/util/uris_spec.rb +118 -0
- data/spec/data/collection-names.txt +438 -0
- data/spec/data/collections.json +4827 -0
- data/spec/data/disjoint-records.xml +187 -0
- data/spec/data/record-184453.xml +58 -0
- data/spec/data/record-184458.xml +63 -0
- data/spec/data/record-187888.xml +78 -0
- data/spec/data/records-api-search-cjk-p1.xml +6381 -0
- data/spec/data/records-api-search-cjk-p2.xml +5 -0
- data/spec/data/records-api-search-p1.xml +4506 -0
- data/spec/data/records-api-search-p2.xml +4509 -0
- data/spec/data/records-api-search-p3.xml +4506 -0
- data/spec/data/records-api-search-p4.xml +4509 -0
- data/spec/data/records-api-search-p5.xml +4506 -0
- data/spec/data/records-api-search-p6.xml +2436 -0
- data/spec/data/records-api-search-p7.xml +5 -0
- data/spec/data/records-api-search.xml +234 -0
- data/spec/data/records-manual-search.xml +547 -0
- data/spec/spec_helper.rb +30 -0
- data/test/profile/table_from_records_profile.rb +46 -0
- metadata +585 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module TIND
|
5
|
+
module Export
|
6
|
+
describe ExportFormat do
|
7
|
+
describe :to_str do
|
8
|
+
it 'returns the value' do
|
9
|
+
ExportFormat.each do |fmt|
|
10
|
+
# rubocop:disable Style/StringConcatenation
|
11
|
+
expect('' + fmt).to eq(fmt.value)
|
12
|
+
# rubocop:enable Style/StringConcatenation
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe :mime_type do
|
18
|
+
it 'returns the correct MIME type' do
|
19
|
+
{
|
20
|
+
ExportFormat::CSV => 'text/csv',
|
21
|
+
ExportFormat::ODS => 'application/vnd.oasis.opendocument.spreadsheet'
|
22
|
+
}.each do |fmt, mime_type|
|
23
|
+
expect(fmt.mime_type).to eq(mime_type)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe :ensure_format do
|
29
|
+
it 'rejects unsupported formats' do
|
30
|
+
expect { ExportFormat.ensure_format(:wks) }.to raise_error(ArgumentError)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe :description do
|
35
|
+
it 'returns a description' do
|
36
|
+
ExportFormat.each do |fmt|
|
37
|
+
expect(fmt.description).to be_a(String)
|
38
|
+
expect(fmt.description).not_to be_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe :DEFAULT do
|
44
|
+
it 'defaults to ODS' do
|
45
|
+
expect(ExportFormat::DEFAULT).to be(ExportFormat::ODS)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe :default? do
|
50
|
+
it 'returns true for default, false otherwise' do
|
51
|
+
ExportFormat.each do |fmt|
|
52
|
+
expect(fmt.default?).to eq(fmt == ExportFormat::DEFAULT)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'berkeley_library/util/strings'
|
3
|
+
|
4
|
+
RSpec::Matchers.define :match_table do |expected_table|
|
5
|
+
match { |actual| diff(expected_table, actual).empty? }
|
6
|
+
|
7
|
+
failure_message do |actual|
|
8
|
+
diff = diff(expected_table, actual)
|
9
|
+
|
10
|
+
msg_elements = ['output differs from table:']
|
11
|
+
diff.each do |(row, col), (v_expected, v_actual)|
|
12
|
+
msg = format_diff_msg(row, col, v_expected, v_actual)
|
13
|
+
msg_elements << msg
|
14
|
+
end
|
15
|
+
msg_elements.join("\n\t")
|
16
|
+
end
|
17
|
+
|
18
|
+
def diff(expected_table, ss_or_csv_str)
|
19
|
+
return diff_spreadsheet(expected_table, ss_or_csv_str) if ss_or_csv_str.respond_to?(:cell)
|
20
|
+
|
21
|
+
diff_csv(expected_table, ss_or_csv_str)
|
22
|
+
end
|
23
|
+
|
24
|
+
def diff_spreadsheet(expected_table, spreadsheet)
|
25
|
+
{}.tap do |diffs|
|
26
|
+
# NOTE: spreadsheet rows are 1-indexed, but row 1 is header
|
27
|
+
expected_table.headers.each_with_index do |expected_header, col|
|
28
|
+
cell_index = [1, 1 + col]
|
29
|
+
next if expected_header == (actual_header = spreadsheet.cell(*cell_index))
|
30
|
+
|
31
|
+
diffs[cell_index] = [expected_header, actual_header]
|
32
|
+
end
|
33
|
+
|
34
|
+
(0..expected_table.row_count).each do |row|
|
35
|
+
ss_row = 2 + row # row 1 is header
|
36
|
+
(0..expected_table.column_count).each do |col|
|
37
|
+
cell_index = [ss_row, 1 + col]
|
38
|
+
expected_value = expected_table.value_at(row, col)
|
39
|
+
actual_value = spreadsheet.cell(*cell_index)
|
40
|
+
next if expected_value == actual_value
|
41
|
+
|
42
|
+
diffs[cell_index] = [expected_value, actual_value]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def diff_csv(expected_table, csv_string)
|
49
|
+
# NOTE: CSV.parse() returns zero-indexed row array
|
50
|
+
csv = CSV.parse(csv_string, headers: false)
|
51
|
+
{}.tap do |diffs|
|
52
|
+
header_row = csv[0]
|
53
|
+
expected_table.headers.each_with_index do |expected_header, col|
|
54
|
+
next if expected_header == (actual_header = header_row[col])
|
55
|
+
|
56
|
+
diffs[[0, col]] = [expected_header, actual_header]
|
57
|
+
end
|
58
|
+
|
59
|
+
(0...expected_table.row_count).each do |row|
|
60
|
+
csv_row = 1 + row # row 1 is header
|
61
|
+
row_values = csv[csv_row] || []
|
62
|
+
(0...expected_table.column_count).each do |col|
|
63
|
+
expected_value = expected_table.value_at(row, col)
|
64
|
+
actual_value = row_values[col]
|
65
|
+
next if expected_value == actual_value
|
66
|
+
|
67
|
+
diffs[[csv_row, col]] = [expected_value, actual_value]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def matching_spreadsheet?(expected_table, spreadsheet)
|
74
|
+
aggregate_failures 'headers' do
|
75
|
+
expected_table.headers.each_with_index do |h, col|
|
76
|
+
ss_col = 1 + col
|
77
|
+
actual_header = spreadsheet.cell(1, ss_col)
|
78
|
+
expect(actual_header).to eq(h), "Expected header #{h.inspect} for column #{ss_col}, got #{actual_header.inspect}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
aggregate_failures 'values' do
|
83
|
+
(0..expected_table.row_count).each do |row|
|
84
|
+
ss_row = 2 + row # row 1 is header
|
85
|
+
(0..expected_table.column_count).each do |col|
|
86
|
+
ss_col = 1 + col
|
87
|
+
expected_value = expected_table.value_at(row, col)
|
88
|
+
actual_value = spreadsheet.cell(ss_row, ss_col)
|
89
|
+
expect(actual_value).to eq(expected_value), "(#{ss_row}, #{ss_col}): expected #{expected_value.inspect}, got #{actual_value.inspect}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# TODO: make this work better
|
96
|
+
def format_diff_msg(row, col, v_expected, v_actual)
|
97
|
+
if (diff_index = BerkeleyLibrary::Util::Strings.diff_index(v_expected, v_actual))
|
98
|
+
<<~MSG
|
99
|
+
(#{row}, #{col}):
|
100
|
+
expected: #{v_expected.inspect}#{' '}
|
101
|
+
got: #{v_actual.inspect}
|
102
|
+
#{' ' * diff_index}^
|
103
|
+
MSG
|
104
|
+
else
|
105
|
+
<<~MSG
|
106
|
+
(#{row}, #{col}):#{' '}
|
107
|
+
expected: #{v_expected.inspect}#{' '}
|
108
|
+
got: #{v_actual.inspect}
|
109
|
+
MSG
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'roo'
|
3
|
+
|
4
|
+
require_relative 'export_matcher'
|
5
|
+
|
6
|
+
module BerkeleyLibrary
|
7
|
+
# noinspection RubyYardParamTypeMatch
|
8
|
+
module TIND
|
9
|
+
describe Export do
|
10
|
+
let(:basename) { File.basename(__FILE__, '.rb') }
|
11
|
+
|
12
|
+
describe 'export' do
|
13
|
+
let(:collection) { 'Bancroft Library' }
|
14
|
+
|
15
|
+
describe 'with results' do
|
16
|
+
|
17
|
+
let(:records) do
|
18
|
+
(1..7)
|
19
|
+
.map { |page| File.read("spec/data/records-api-search-p#{page}.xml") }
|
20
|
+
.map { |p| BerkeleyLibrary::TIND::MARC::XMLReader.new(p, freeze: true).to_a }
|
21
|
+
.flatten
|
22
|
+
end
|
23
|
+
let(:expected_table) { Export::Table.from_records(records, freeze: true, exportable_only: true) }
|
24
|
+
|
25
|
+
before(:each) do
|
26
|
+
search = instance_double(BerkeleyLibrary::TIND::API::Search)
|
27
|
+
allow(search).to receive(:each_result).with(freeze: true).and_return(records.each)
|
28
|
+
allow(BerkeleyLibrary::TIND::API::Search).to receive(:new).with(collection: collection).and_return(search)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe :export do
|
32
|
+
describe 'CSV formats' do
|
33
|
+
it 'defaults to CSV' do
|
34
|
+
actual_csv = Export.export(collection)
|
35
|
+
expect(actual_csv).to match_table(expected_table)
|
36
|
+
end
|
37
|
+
|
38
|
+
[Export::ExportFormat::CSV, :csv, 'CSV'].each do |fmt|
|
39
|
+
it "accepts #{fmt.inspect} as a format parameter" do
|
40
|
+
actual_csv = Export.export(collection, fmt)
|
41
|
+
expect(actual_csv).to match_table(expected_table)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'ODS formats' do
|
47
|
+
[Export::ExportFormat::ODS, :ods, 'ODS'].each_with_index do |fmt, i|
|
48
|
+
it "accepts #{fmt.inspect} as a format parameter" do
|
49
|
+
Dir.mktmpdir(basename) do |dir|
|
50
|
+
output_path = File.join(dir, "#{basename}-#{i}.ods")
|
51
|
+
Export.export(collection, fmt, output_path)
|
52
|
+
|
53
|
+
ss = Roo::Spreadsheet.open(output_path)
|
54
|
+
begin
|
55
|
+
expect(ss).to match_table(expected_table)
|
56
|
+
ensure
|
57
|
+
ss.close
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'without results' do
|
67
|
+
before(:each) do
|
68
|
+
search = instance_double(BerkeleyLibrary::TIND::API::Search)
|
69
|
+
allow(search).to receive(:each_result).with(freeze: true).and_return([].each)
|
70
|
+
allow(BerkeleyLibrary::TIND::API::Search).to receive(:new).with(collection: collection).and_return(search)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'raises NoResultsError' do
|
74
|
+
expect { Export.export(collection) }.to raise_error(Export::NoResultsError)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'CJK support' do
|
79
|
+
let(:collection) { 'Houcun ju shi ji' }
|
80
|
+
let(:records) { BerkeleyLibrary::TIND::MARC::XMLReader.new('spec/data/records-api-search-cjk-p1.xml', freeze: true).to_a }
|
81
|
+
let(:expected_table) { Export::Table.from_records(records, freeze: true, exportable_only: true) }
|
82
|
+
|
83
|
+
before(:each) do
|
84
|
+
search = instance_double(BerkeleyLibrary::TIND::API::Search)
|
85
|
+
allow(search).to receive(:each_result).with(freeze: true).and_return(records.each)
|
86
|
+
allow(BerkeleyLibrary::TIND::API::Search).to receive(:new).with(collection: collection).and_return(search)
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'LibreOffice' do
|
90
|
+
it 'works for LibreOffice' do
|
91
|
+
Dir.mktmpdir(basename) do |dir|
|
92
|
+
output_path = File.join(dir, "#{basename}.ods")
|
93
|
+
Export.export(collection, 'ods', output_path)
|
94
|
+
|
95
|
+
ss = Roo::Spreadsheet.open(output_path)
|
96
|
+
begin
|
97
|
+
expect(ss).to match_table(expected_table)
|
98
|
+
ensure
|
99
|
+
ss.close
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'writes to an exploded directory' do
|
105
|
+
Dir.mktmpdir(basename) do |dir|
|
106
|
+
Export.export(collection, 'ods', dir)
|
107
|
+
|
108
|
+
expected_paths_relative = %w[META-INF/manifest.xml styles.xml content.xml]
|
109
|
+
expected_paths_absolute = expected_paths_relative.map do |path_relative|
|
110
|
+
joined_path = File.join(dir, path_relative)
|
111
|
+
File.absolute_path(joined_path)
|
112
|
+
end
|
113
|
+
|
114
|
+
expected_paths_absolute.each do |path_absolute|
|
115
|
+
expect(File.file?(path_absolute)).to eq(true)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'works for CSV' do
|
122
|
+
actual_csv = Export.export(collection, 'csv')
|
123
|
+
expect(actual_csv).to match_table(expected_table)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'with no results' do
|
129
|
+
let(:collection) { 'Not a collection' }
|
130
|
+
|
131
|
+
before(:each) do
|
132
|
+
search = instance_double(BerkeleyLibrary::TIND::API::Search)
|
133
|
+
empty_enumerator = Enumerator.new({})
|
134
|
+
allow(search).to receive(:each_result).and_return(empty_enumerator)
|
135
|
+
allow(BerkeleyLibrary::TIND::API::Search).to receive(:new).with(collection: collection).and_return(search)
|
136
|
+
end
|
137
|
+
|
138
|
+
describe :export do
|
139
|
+
it 'raises an error' do
|
140
|
+
Export::ExportFormat.each do |fmt|
|
141
|
+
out = instance_double(IO)
|
142
|
+
%i[reopen rewind << write].each { |m| expect(out).not_to receive(m) }
|
143
|
+
expect { Export.export(collection, fmt, out) }.to raise_error(Export::NoResultsError)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'roo'
|
3
|
+
|
4
|
+
require_relative 'export_matcher'
|
5
|
+
|
6
|
+
module BerkeleyLibrary
|
7
|
+
module TIND
|
8
|
+
module Export
|
9
|
+
describe Exporter do
|
10
|
+
let(:collection) { 'Bancroft Library' }
|
11
|
+
|
12
|
+
describe 'base class' do
|
13
|
+
let(:exporter) { Exporter.new(collection) }
|
14
|
+
|
15
|
+
it "doesn't implement :export" do
|
16
|
+
expect { exporter.export }.to raise_error(NoMethodError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "doesn't respond to :export" do
|
20
|
+
expect(exporter.respond_to?('export')).to eq(false)
|
21
|
+
expect(exporter.respond_to?(:export)).to eq(false)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Export::ExportFormat.each do |export_format|
|
26
|
+
|
27
|
+
attr_reader :search
|
28
|
+
|
29
|
+
before(:each) do
|
30
|
+
@search = instance_double(BerkeleyLibrary::TIND::API::Search)
|
31
|
+
allow(BerkeleyLibrary::TIND::API::Search).to receive(:new).with(collection: collection).and_return(search)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe export_format.to_s do
|
35
|
+
let(:ext) { export_format.to_s.downcase }
|
36
|
+
let(:exporter) { export_format.exporter_for(collection) }
|
37
|
+
|
38
|
+
it 'responds to :export' do
|
39
|
+
expect(exporter.respond_to?('export')).to eq(true)
|
40
|
+
expect(exporter.respond_to?(:export)).to eq(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'with results' do
|
44
|
+
let(:records) do
|
45
|
+
(1..7)
|
46
|
+
.map { |page| File.read("spec/data/records-api-search-p#{page}.xml") }
|
47
|
+
.map { |p| BerkeleyLibrary::TIND::MARC::XMLReader.new(p, freeze: true).to_a }
|
48
|
+
.flatten
|
49
|
+
end
|
50
|
+
|
51
|
+
before(:each) do
|
52
|
+
allow(search).to receive(:each_result).with(freeze: true).and_return(records.each)
|
53
|
+
end
|
54
|
+
|
55
|
+
describe :any_results? do
|
56
|
+
it 'returns true' do
|
57
|
+
expect(exporter.any_results?).to eq(true)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'caches the search result' do
|
61
|
+
2.times { exporter.any_results? }
|
62
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe :export do
|
67
|
+
it 'exports' do
|
68
|
+
exported_data = exporter.export
|
69
|
+
expect(exported_data).not_to be_nil
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'caches search results' do
|
73
|
+
2.times { expect(exporter.export).not_to be_nil }
|
74
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'caches search results from a previous `has_results?` invocation' do
|
78
|
+
exporter.any_results?
|
79
|
+
exporter.export
|
80
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'without results' do
|
86
|
+
before(:each) do
|
87
|
+
allow(search).to receive(:each_result).with(freeze: true).and_return([].each)
|
88
|
+
end
|
89
|
+
|
90
|
+
describe :any_results? do
|
91
|
+
it 'returns false' do
|
92
|
+
expect(exporter.any_results?).to eq(false)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'caches the search result' do
|
96
|
+
2.times { exporter.any_results? }
|
97
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe :export do
|
102
|
+
it 'raises NoResultsError' do
|
103
|
+
expect { exporter.export }.to raise_error(NoResultsError)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'caches the failed search result' do
|
107
|
+
2.times do
|
108
|
+
expect { exporter.export }.to raise_error(NoResultsError)
|
109
|
+
end
|
110
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'caches the failed search result from a previous `has_results?` invocation' do
|
114
|
+
exporter.any_results?
|
115
|
+
expect { exporter.export }.to raise_error(NoResultsError)
|
116
|
+
expect(search).to have_received(:each_result).with(freeze: true).exactly(1).time
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|