Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ defs:
AU: ['au.yaml']
BE_FR: ['be_fr.yaml']
BE_NL: ['be_nl.yaml']
BR: ['br.yaml']
BG: ['bg.yaml']
BR: ['br.yaml']
BY: ['by.yaml']
CA: ['ca.yaml', 'northamericainformal.yaml']
CH: ['ch.yaml']
Expand All @@ -17,43 +17,40 @@ defs:
CR: ['cr.yaml']
CY: ['cy.yaml']
CZ: ['cz.yaml']
DK: ['dk.yaml']
DE: ['de.yaml']
ECBTARGET: ['ecbtarget.yaml']
DK: ['dk.yaml']
EE: ['ee.yaml']
ES: ['es.yaml']
FederalReserve: ['federalreserve.yaml']
FederalReserveBanks: ['federalreservebanks.yaml']
FedEx: ['fedex.yaml']
FI: ['fi.yaml']
FR: ['fr.yaml']
GB: ['gb.yaml']
GE: ['ge.yaml']
GR: ['gr.yaml']
HR: ['hr.yaml']
HK: ['hk.yaml']
HR: ['hr.yaml']
HU: ['hu.yaml']
IE: ['ie.yaml']
IL: ['il.yaml']
IN: ['in.yaml']
IS: ['is.yaml']
IT: ['it.yaml']
JP: ['jp.yaml']
KE: ['ke.yaml']
KR: ['kr.yaml']
KZ: ['kz.yaml']
LI: ['li.yaml']
LT: ['lt.yaml']
LU: ['lu.yaml']
LV: ['lv.yaml']
MA: ['ma.yaml']
MC: ['mc.yaml']
MT_MT: ['mt_mt.yaml']
MT_EN: ['mt_en.yaml']
MT_MT: ['mt_mt.yaml']
MX: ['mx.yaml', 'northamericainformal.yaml']
NERC: ['nerc.yaml']
MY: ['my.yaml']
NG: ['ng.yaml']
NL: ['nl.yaml']
LU: ['lu.yaml']
"NO": ['no.yaml']
NYSE: ['nyse.yaml']
NZ: ['nz.yaml']
PE: ['pe.yaml']
PH: ['ph.yaml']
Expand All @@ -64,24 +61,29 @@ defs:
RS_LA: ['rs_la.yaml']
RU: ['ru.yaml']
SE: ['se.yaml']
SG: ['sg.yaml']
SI: ['si.yaml']
SK: ['sk.yaml']
TH: ['th.yaml']
TN: ['tn.yaml']
TR: ['tr.yaml']
TSX: ['tsx.yaml']
UA: ['ua.yaml']
US: ['us.yaml', 'northamericainformal.yaml']
UnitedNations: ['unitednations.yaml']
UPS: ['ups.yaml']
VE: ['ve.yaml']
VN: ['vn.yaml']
ZA: ['za.yaml']
# Meta regions
Europe: ['at.yaml', 'be_fr.yaml', 'be_nl.yaml', 'ch.yaml', 'cz.yaml', 'dk.yaml', 'de.yaml', 'es.yaml', 'fr.yaml', 'gb.yaml', 'gr.yaml', 'hr.yaml', 'hu.yaml', 'ie.yaml', 'is.yaml', 'it.yaml', 'li.yaml', 'lt.yaml', 'lv.yaml', 'nl.yaml', 'no.yaml', 'pl.yaml', 'pt.yaml', 'ro.yaml', 'sk.yaml', 'si.yaml', 'bg.yaml', 'ua.yaml']
NorthAmerica: ['ca.yaml', 'mx.yaml', 'us.yaml', 'northamericainformal.yaml']
SouthAmerica: ['ar.yaml', 'br.yaml', 'cl.yaml', 'co.yaml', 'pe.yaml', 've.yaml']
Scandinavia: ['dk.yaml', 'is.yaml', 'no.yaml', 'se.yaml', 'fi.yaml']
Europe: ['at.yaml', 'be_fr.yaml', 'be_nl.yaml', 'ch.yaml', 'cz.yaml', 'dk.yaml', 'de.yaml', 'es.yaml', 'fr.yaml', 'gb.yaml', 'gr.yaml', 'hr.yaml', 'hu.yaml', 'ie.yaml', 'is.yaml', 'it.yaml', 'li.yaml', 'lt.yaml', 'lv.yaml', 'nl.yaml', 'no.yaml', 'pl.yaml', 'pt.yaml', 'ro.yaml', 'sk.yaml', 'si.yaml', 'bg.yaml', 'ua.yaml']
JP: ['jp.yaml']
VE: ['ve.yaml']
VN: ['vn.yaml']
SK: ['sk.yaml']
SI: ['si.yaml']
SG: ['sg.yaml']
MY: ['my.yaml']
TH: ['th.yaml']
NG: ['ng.yaml']
SouthAmerica: ['ar.yaml', 'br.yaml', 'cl.yaml', 'co.yaml', 'pe.yaml', 've.yaml']
# Organisations
ECBTARGET: ['ecbtarget.yaml']
FederalReserve: ['federalreserve.yaml']
FederalReserveBanks: ['federalreservebanks.yaml']
FedEx: ['fedex.yaml']
NERC: ['nerc.yaml']
NYSE: ['nyse.yaml']
TSX: ['tsx.yaml']
UnitedNations: ['unitednations.yaml']
UPS: ['ups.yaml']
26 changes: 26 additions & 0 deletions lib/validation/index_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Index
def call(index, definition_files)
defs = validate_structure!(index)

validate_order!(defs.keys)
validate_file_names!(defs)
validate_all_files_indexed!(defs, definition_files)
validate_all_indexed_files_exist!(defs, definition_files)
Expand Down Expand Up @@ -47,6 +48,31 @@ def validate_structure!(index)
defs
end

def validate_order!(order)
expected_order = order.sort_by do |name|
group = case name
when /\A[A-Z]{2}(\z|_)/
0 # countries
when *AGGREGATE_REGIONS
1 # meta regions
else
2 # organisations
end

[group, name.downcase]
end

unless order == expected_order
out_of_order = order.each_index.select{ |i| order[i] != expected_order[i] }

diff = out_of_order.chunk_while{ |a, b| a + 1 == b }.flat_map do |chunk|
chunk.map{ |i| "-#{order[i]}" } + chunk.map{ |i| "+#{expected_order[i]}" }
end

raise Errors::InvalidIndex.new("index has wrong order of definitions:\n#{diff.join("\n")}")
end
end

def validate_file_names!(defs)
invalid = indexed_files(defs).reject { |file| file =~ VALID_FILE_NAME }

Expand Down
78 changes: 69 additions & 9 deletions spec/validation/index_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
describe Definitions::Validation::Index do
subject { described_class.new }

let(:index) { { 'defs' => { 'US' => ['us.yaml'], 'CA' => ['ca.yaml'] } } }
let(:index) { { 'defs' => { 'CA' => ['ca.yaml'], 'US' => ['us.yaml'] } } }
let(:definition_files) { ['us.yaml', 'ca.yaml'] }

context 'valid' do
Expand All @@ -25,14 +25,14 @@
it 'allows aggregate regions to have no definition file of their own' do
index = {
'defs' => {
'BR' => ['br.yaml'],
'FR' => ['fr.yaml'],
'NO' => ['no.yaml'],
'US' => ['us.yaml'],
'Europe' => ['fr.yaml'],
'NorthAmerica' => ['us.yaml'],
'Scandinavia' => ['no.yaml'],
'SouthAmerica' => ['br.yaml'],
'FR' => ['fr.yaml'],
'US' => ['us.yaml'],
'NO' => ['no.yaml'],
'BR' => ['br.yaml'],
}
}
expect(subject.call(index, ['fr.yaml', 'us.yaml', 'no.yaml', 'br.yaml'])).to be true
Expand Down Expand Up @@ -89,6 +89,66 @@
end
end

context 'invalid order' do
it 'raises error if the country codes are not ordered' do
index = { 'defs' => { 'US' => ['us.yaml'], 'CA' => ['ca.yaml'] } }
expect { subject.call(index, ['us.yaml', 'us.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index has wrong order of definitions:\n-US\n-CA\n+CA\n+US")
}
end

it 'raises error if meta regions are not ordered' do
index = {
'defs' => {
'FR' => ['fr.yaml'],
'US' => ['us.yaml'],
'NorthAmerica' => ['us.yaml'],
'Europe' => ['fr.yaml'],
}
}
expect { subject.call(index, ['fr.yaml', 'us.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index has wrong order of definitions:\n-NorthAmerica\n-Europe\n+Europe\n+NorthAmerica")
}
end

it 'raises error if organisation names are not ordered' do
index = {
'defs' => {
'Foo' => ['foo.yaml'],
'Bar' => ['bar.yaml'],
}
}
expect { subject.call(index, ['foo.yaml', 'bar.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index has wrong order of definitions:\n-Foo\n-Bar\n+Bar\n+Foo")
}
end

it 'raises error if meta regions precede country codes' do
index = {
'defs' => {
'Europe' => ['fr.yaml'],
'FR' => ['fr.yaml'],
}
}
expect { subject.call(index, ['fr.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index has wrong order of definitions:\n-Europe\n-FR\n+FR\n+Europe")
}
end

it 'raises error if organisation precede meta regions' do
index = {
'defs' => {
'FR' => ['fr.yaml'],
'Foo' => ['foo.yaml'],
'Europe' => ['fr.yaml'],
}
}
expect { subject.call(index, ['fr.yaml', 'foo.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index has wrong order of definitions:\n-Foo\n-Europe\n+Europe\n+Foo")
}
end
end

context 'invalid file names' do
it 'raises error if an indexed file is uppercase' do
index = { 'defs' => { 'US' => ['US.yaml'] } }
Expand Down Expand Up @@ -130,14 +190,14 @@

context 'indexed files that do not exist' do
it 'raises error if the index lists a file that is not on disk' do
index = { 'defs' => { 'US' => ['us.yaml'], 'HK' => ['hk.yaml'] } }
index = { 'defs' => { 'HK' => ['hk.yaml'], 'US' => ['us.yaml'] } }
expect { subject.call(index, ['us.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index.yaml lists files that do not exist: hk.yaml")
}
end

it 'reports every missing file, sorted' do
index = { 'defs' => { 'US' => ['us.yaml', 'zz.yaml'], 'HK' => ['hk.yaml'] } }
index = { 'defs' => { 'HK' => ['hk.yaml'], 'US' => ['us.yaml', 'zz.yaml'] } }
expect { subject.call(index, ['us.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to eq("index.yaml lists files that do not exist: hk.yaml, zz.yaml")
}
Expand All @@ -154,14 +214,14 @@
end

it 'reports every mismatched region, sorted' do
index = { 'defs' => { 'US' => ['ca.yaml'], 'GB' => ['ca.yaml'] } }
index = { 'defs' => { 'GB' => ['ca.yaml'], 'US' => ['ca.yaml'] } }
expect { subject.call(index, ['ca.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to include("index entries do not list their own definition file: GB (expected 'gb.yaml'), US (expected 'us.yaml')")
}
end

it 'raises error for a region that is not a known aggregate' do
index = { 'defs' => { 'Asia' => ['jp.yaml'], 'JP' => ['jp.yaml'] } }
index = { 'defs' => { 'JP' => ['jp.yaml'], 'Asia' => ['jp.yaml'] } }
expect { subject.call(index, ['jp.yaml']) }.to raise_error(Definitions::Errors::InvalidIndex) { |e|
expect(e.message).to include("Asia (expected 'asia.yaml')")
}
Expand Down
Loading