# Copyright (c) 2020 Jerome Arbez-Gindre # frozen_string_literal: true require('defmastership/document') RSpec.describe(Defmastership::Document) do subject(:document) { described_class.new } describe '.new' do it { is_expected.not_to(be_nil) } it { is_expected.to(have_attributes(definitions: [])) } it { is_expected.to(have_attributes(eref: {})) } it { is_expected.to(have_attributes(iref: false)) } it { is_expected.to(have_attributes(attributes: {})) } it { is_expected.to(have_attributes(variables: {})) } end describe '.method_missing' do it do expect { document.not_implemented_random_method } .to(raise_error(NoMethodError)) end end describe '.respond_to_missing?' do it { expect(document.respond_to?(:add_new_definition)).to(be(true)) } it { expect(document.respond_to?(:not_implemented_random_method)).to(be(false)) } end describe '#do_parse' do context 'with valid definitions' do let(:definition) { instance_double(Defmastership::Definition, 'definition') } before do allow(Defmastership::Definition).to(receive(:new).and_return(definition)) allow(definition).to( receive_messages( labels: Set.new, '<<': definition, add_eref: definition, add_iref: definition ) ) end context 'when simple definition line' do let(:input_lines) { ['[define, requirement, TOTO-0001]'] } before do allow(Defmastership::Definition).to( receive(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001') ).and_return(definition) ) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001') ) ) end it { expect(document).to(have_attributes(definitions: [definition])) } it { expect(definition).to(have_received(:labels)) } end context 'when simple definition line with explicit checksum' do let(:input_lines) { ['[define, requirement, TOTO-0001(~ab12)]'] } before do allow(Defmastership::Definition).to( receive(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', explicit_checksum: '~ab12') ).and_return(definition) ) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', explicit_checksum: '~ab12') ) ) end end context 'when simple definition line with explicit version' do let(:input_lines) { ['[define, requirement, TOTO-0001(pouet)]'] } before do allow(Defmastership::Definition).to( receive(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', explicit_version: 'pouet') ).and_return(definition) ) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', explicit_version: 'pouet') ) ) end end context 'when complete definition with content' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', '--', 'a', 'b', '--', 'not included' ] end before do allow(definition).to(receive(:<<).and_return(definition)) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:<<).with('a')) } it { expect(definition).to(have_received(:<<).with('b')) } end context 'when complete definition with content including ----' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', '--', '----', 'a', 'b', '----', '--', 'not included' ] end before do allow(definition).to(receive(:<<).and_return(definition)) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:<<).twice.with('----')) } it { expect(definition).to(have_received(:<<).with('a')) } it { expect(definition).to(have_received(:<<).with('b')) } end context 'when complete definition with single line comment' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', '--', '// comment', '--', 'not included' ] end before do allow(definition).to(receive(:<<).and_return(definition)) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:<<).with('// comment')) } end context 'when definition with one paragraph' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'one line', 'another line', '', 'not included' ] end before do allow(definition).to(receive(:<<).and_return(definition)) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:<<).with('one line')) } it { expect(definition).to(have_received(:<<).with('another line')) } end context 'when definition with one paragraph followed by a block' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'one line', 'another line', '--', 'not included', '--' ] end before { document.__send__(:do_parse, input_lines) } it { expect(definition).not_to(have_received(:<<).with('not included')) } end context 'when block without definition' do let(:input_lines) { ['--', 'first line', '--'] } it do document.__send__(:do_parse, input_lines) expect(document.definitions).to(eq([])) end end context 'when definition with labels' do let(:input_lines) do [ '[define, requirement, TOTO-0001, [label1, label2]]', 'one line', 'not included' ] end before do allow(definition).to(receive(:labels).and_return(Set['bla1', 'bla2'])) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', labels: 'label1, label2') ) ) end it { expect(document.labels).to(eq(Set['bla1', 'bla2'])) } end context 'when definition with labels without spaces' do let(:input_lines) do [ '[define,requirement,TOTO-0001,[label1,label2]]', 'one line', 'not included' ] end before do allow(definition).to(receive(:labels).and_return(Set['bla1', 'bla2'])) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001', labels: 'label1,label2') ) ) end it { expect(document.labels).to(eq(Set['bla1', 'bla2'])) } end context 'when setup external links' do let(:input_lines) do [ ':eref-implements-prefix: Participate to:', ':eref-implements-url: ./other_document.html', 'one line', 'not included' ] end before { document.__send__(:do_parse, input_lines) } it { expect(document.eref[:implements]).to(eq(prefix: 'Participate to:', url: './other_document.html')) } end context 'when setup external links without url' do let(:input_lines) do [ ':eref-implements-prefix: Participate to:', 'one line', 'not included' ] end it do document.__send__(:do_parse, input_lines) expect(document.eref[:implements]) .to(eq(prefix: 'Participate to:')) end end context 'when define external links' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'one line', 'defs:eref[implements, [SYSTEM-0012, SYSTEM-0014]]' ] end before do allow(definition).to( receive(:add_eref).with(:implements, 'SYSTEM-0012, SYSTEM-0014') .and_return(definition) ) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:add_eref).with(:implements, 'SYSTEM-0012, SYSTEM-0014')) } end context 'when define internal links' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'defs:iref[toto] defs:iref[tutu]', 'defs:iref[pouet]' ] end before do allow(definition).to(receive(:add_iref)) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:add_iref).with('toto')) } it { expect(definition).to(have_received(:add_iref).with('tutu')) } it { expect(definition).to(have_received(:add_iref).with('pouet')) } it { expect(document.iref).to(be(true)) } end context 'when configure attributes' do let(:input_lines) do [ ':attr-myattribute-prefix: My attribute:', ':attr-myotherone-prefix: My other attribute:' ] end before { document.__send__(:do_parse, input_lines) } it { expect(document.attributes).to(eq(myattribute: 'My attribute:', myotherone: 'My other attribute:')) } end context 'when setup attributes value' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'defs:attribute[myattribute, My value]' ] end before do allow(definition).to(receive(:set_attribute).with(:myattribute, 'My value')) document.__send__(:do_parse, input_lines) end it { expect(definition).to(have_received(:set_attribute).with(:myattribute, 'My value')) } end context 'when putting comments' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', '// defs:iref[toto] defs:iref[tutu]' ] end it do document.__send__(:do_parse, input_lines) expect(document.iref).to(be(false)) end end context 'when definition in wrong literal block' do let(:input_lines) do [ '1234', '[define, requirement, TOTO-0001]' ] end before do allow(Defmastership::Definition).to( receive(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001') ).and_return(definition) ) document.__send__(:do_parse, input_lines) end it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001') ) ) end end end context 'when variables replacement' do let(:definition) { instance_double(Defmastership::Definition, 'definition') } before do allow(Defmastership::Definition).to(receive(:new).and_return(definition)) allow(definition).to( receive_messages( labels: Set.new, '<<': definition ) ) document.__send__(:do_parse, input_lines) end context 'when defined variable' do let(:input_lines) do [ ':variable: one value', '[define, requirement, TOTO-0001]', 'bef {variable} aft' ] end it { expect(document).to(have_attributes(variables: { variable: 'one value' })) } it { expect(definition).to(have_received(:<<).with('bef one value aft')) } end context 'when not defined variable' do let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'bef {variable} aft' ] end it { expect(definition).to(have_received(:<<).with('bef {variable} aft')) } end context 'when badly defined variable' do let(:input_lines) do [ ':variable:one value', '[define, requirement, TOTO-0001]', 'bef {variable} aft' ] end it { expect(definition).to(have_received(:<<).with('bef {variable} aft')) } end context 'when multiple defined variables' do let(:input_lines) do [ ':variable: one', ':variable2: two', '[define, requirement, TOTO-0001]', 'bef {variable} {variable2} aft' ] end it { expect(definition).to(have_received(:<<).with('bef one two aft')) } end end context 'with invalid definitions' do context 'when definition in literal block' do let(:input_lines) do [ '....', '[define, requirement, TOTO-0001]', '....' ] end before do allow(Defmastership::Definition).to( receive(:new).and_raise('not a valide definition') ) end it do document.__send__(:do_parse, input_lines) expect(document).to(have_attributes(definitions: [])) end end context 'when definition in comment block' do let(:input_lines) do [ '////', '[define, requirement, TOTO-0001]', '////' ] end before do allow(Defmastership::Definition).to( receive(:new).and_raise('not a valide definition') ) end it do document.__send__(:do_parse, input_lines) expect(document).to(have_attributes(definitions: [])) end end end end describe '#parse_file_with_preprocessor' do let(:definition) { instance_double(Defmastership::Definition, 'definition') } let(:input_lines) { ['[define, requirement, TOTO-0001]'] } let(:adoc_doc) { instance_double(Asciidoctor::Document, 'adoc_doc') } let(:adoc_reader) { instance_double(Asciidoctor::Reader, 'adoc_reader') } before do allow(Asciidoctor).to( receive(:load_file).with('the_file.adoc', { parse: false, safe: :unsafe }).and_return(adoc_doc) ) allow(adoc_doc).to(receive(:reader).and_return(adoc_reader)) allow(adoc_reader).to(receive(:read_lines).and_return(input_lines)) allow(Defmastership::Definition).to(receive(:new).and_return(definition)) allow(definition).to( receive_messages( '<<': definition, labels: Set.new ) ) document.parse_file_with_preprocessor('the_file.adoc') end it { expect(Asciidoctor).to(have_received(:load_file).with('the_file.adoc', { parse: false, safe: :unsafe })) } it { expect(adoc_doc).to(have_received(:reader).with(no_args)) } it { expect(adoc_reader).to(have_received(:read_lines).with(no_args)) } it do expect(Defmastership::Definition).to( have_received(:new).with( matchdata_including(type: 'requirement', reference: 'TOTO-0001') ) ) end end describe '#wrong_explicit_checksum?' do let(:defs) do [ instance_double(Defmastership::Definition, 'definition'), instance_double(Defmastership::Definition, 'definition') ] end let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'def one', '', '[define, requirement, TOTO-0002]', 'def two' ] end before do allow(Defmastership::Definition).to(receive(:new).twice.and_return(defs.first, defs[1])) defs.each do |definition| allow(definition).to(receive(:labels)).and_return([]) allow(definition).to(receive(:<<)).and_return(definition) end end context 'when no wrong explicit checksum' do before do defs.each { |definition| allow(definition).to(receive(:wrong_explicit_checksum)).and_return(nil) } document.__send__(:do_parse, input_lines) document.wrong_explicit_checksum? end it { expect(defs.first).to(have_received(:wrong_explicit_checksum)) } it { expect(defs[1]).to(have_received(:wrong_explicit_checksum)) } it { expect(document.wrong_explicit_checksum?).to(be(false)) } end context 'when one req has wrong explicit checksum' do before do allow(defs.first).to(receive(:wrong_explicit_checksum)).and_return('toto') allow(defs[1]).to(receive(:wrong_explicit_checksum)).and_return(nil) document.__send__(:do_parse, input_lines) document.wrong_explicit_checksum? end it { expect(document.wrong_explicit_checksum?).to(be(true)) } end end describe '#explicit_version?' do let(:defs) do [ instance_double(Defmastership::Definition, 'definition'), instance_double(Defmastership::Definition, 'definition') ] end let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'def one', '', '[define, requirement, TOTO-0002]', 'def two' ] end before do allow(Defmastership::Definition).to(receive(:new).twice.and_return(defs.first, defs[1])) allow(defs.first).to(receive(:labels)).and_return([]) allow(defs[1]).to(receive(:labels)).and_return([]) allow(defs.first).to(receive(:<<).and_return(defs.first)) allow(defs[1]).to(receive(:<<).and_return(defs[1])) end context 'when no explicit version' do before do allow(defs.first).to(receive(:explicit_version)).and_return(nil) allow(defs[1]).to(receive(:explicit_version)).and_return(nil) document.__send__(:do_parse, input_lines) document.explicit_version? end it { expect(defs.first).to(have_received(:explicit_version)) } it { expect(defs[1]).to(have_received(:explicit_version)) } it { expect(document.explicit_version?).to(be(false)) } end context 'when one req has explicit version' do before do allow(defs.first).to(receive(:explicit_version)).and_return('toto') allow(defs[1]).to(receive(:explicit_version)).and_return(nil) document.__send__(:do_parse, input_lines) document.explicit_version? end it { expect(document.explicit_version?).to(be(true)) } end end describe '#ref_to_def?' do let(:definitions) do [ instance_double(Defmastership::Definition, 'def1'), instance_double(Defmastership::Definition, 'def2') ] end let(:input_lines) do [ '[define, requirement, TOTO-0001]', 'def one', '', '[define, requirement, TOTO-0002(~1234)]', 'def two' ] end before do allow(Defmastership::Definition).to(receive(:new).twice.and_return(definitions.first, definitions[1])) allow(definitions.first).to( receive_messages( labels: [], '<<': definitions.first, reference: 'TOTO-0001' ) ) allow(definitions[1]).to( receive_messages( labels: [], '<<': definitions[1], reference: 'TOTO-0002' ) ) document.__send__(:do_parse, input_lines) end it { expect(document.ref_to_def('TOTO-0001')).to(eq(definitions.first)) } it { expect(document.ref_to_def('TOTO-0002')).to(eq(definitions[1])) } end end