#-- copyright # OpenProject is an open source project management software. # Copyright (C) 2012-2021 the OpenProject GmbH # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License version 3. # # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: # Copyright (C) 2006-2013 Jean-Philippe Lang # Copyright (C) 2010-2013 the ChiliProject Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # See COPYRIGHT and LICENSE files for more details. #++ shared_context 'custom actions action' do let(:instance) do described_class.new end let(:expected_key) do if defined?(key) key else raise ":key needs to be defined" end end let(:expected_type) do if defined?(type) type else raise ":type needs to be defined" end end end shared_examples_for 'base custom action' do include_context 'custom actions action' let(:expected_priority) do if defined?(priority) priority else 100 end end let(:expected_value) do if defined?(value) value else 1 end end describe '.all' do it 'is an array with the class itself' do expect(described_class.all) .to match_array [described_class] end end describe '.key' do it 'is the expected key' do expect(described_class.key) .to eql(expected_key) end end describe '#key' do it 'is the expected key' do expect(instance.key) .to eql(expected_key) end end describe '#values' do it 'can be provided on initialization' do i = described_class.new(expected_value) expect(i.values) .to eql [expected_value] end it 'can be set and read' do instance.values = expected_value expect(instance.values) .to eql [expected_value] end end describe '#human_name' do it 'is the human_attribute_name' do expect(instance.human_name) .to eql(WorkPackage.human_attribute_name(expected_key)) end end describe '#type' do it 'is the expected type' do expect(instance.type) .to eql(expected_type) end end describe '#priority' do it 'is the expected level' do expect(instance.priority) .to eql(expected_priority) end end end shared_examples_for 'associated custom action' do include_context 'custom actions action' do describe '#apply' do let(:work_package) { FactoryBot.build_stubbed(:stubbed_work_package) } it 'sets the associated_id in the work package to the action\'s value' do expect(work_package) .to receive(:"#{key}_id=") .with(42) instance.values = 42 instance.apply(work_package) end end it_behaves_like 'associated custom action validations' end end shared_examples_for 'associated custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if values not from list of allowed values' do instance.values = [0] instance.validate(errors) expect(errors.symbols_for(:actions)) .to eql [:inclusion] end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = allowed_values.map { |a| a[:value] } instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else # For reasons beyond me, an :include is sometimes also # part of the errors array. Have to weaken the test until somebody figures it out. expect(errors.symbols_for(:actions)) .to include :only_one_allowed end end end end shared_examples_for 'bool custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if values not true or false' do instance.values = ['some bogus'] instance.validate(errors) expect(errors.symbols_for(:actions)) .to eql [:inclusion] end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = allowed_values.map(&:values).flatten instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else expect(errors.symbols_for(:actions)) .to eql [:only_one_allowed] end end end end shared_examples_for 'int custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [1, 2] instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else expect(errors.symbols_for(:actions)) .to eql [:only_one_allowed] end end end end shared_examples_for 'float custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [1.252, 2.123] instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else expect(errors.symbols_for(:actions)) .to eql [:only_one_allowed] end end end end shared_examples_for 'string custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = %w(some values) instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else expect(errors.symbols_for(:actions)) .to eql [:only_one_allowed] end end end end shared_examples_for 'text custom action validations' do it_behaves_like 'string custom action validations' end shared_examples_for 'date custom action validations' do describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) if instance.required? expect(errors.symbols_for(:actions)) .to eql [:empty] else expect(errors.symbols_for(:actions)) .to be_empty end end it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [Date.today + 4.days, Date.today - 5.days] instance.validate(errors) if instance.multi_value? expect(errors.symbols_for(:actions)) .to be_empty else expect(errors.symbols_for(:actions)) .to eql [:only_one_allowed] end end end end shared_examples_for 'associated values transformation' do it_behaves_like 'int values transformation' end shared_examples_for 'int values transformation' do describe '#values' do it 'transforms the values to integers' do instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to match_array [42, nil, 23] end end end shared_examples_for 'float values transformation' do describe '#values' do it 'transforms the values to integers' do instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to match_array [42, nil, 23, 12.34234] end end end shared_examples_for 'string values transformation' do describe '#values' do it 'transforms the values to integers' do instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to match_array ['42', nil, '23', 'some bogus', '12.34234', '42a34e324r32'] end end end shared_examples_for 'text values transformation' do describe '#values' do it 'transforms the values to integers' do instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to match_array ['42', nil, '23', 'some bogus', '12.34234', '42a34e324r32'] end end end shared_examples_for 'date values transformation' do describe '#values' do it 'transforms the values to integers' do instance.values = ["2015-03-29", Date.today, nil, (Date.today - 1.day).to_datetime, 'bogus', '%CURRENT_DATE%'] expect(instance.values) .to match_array [Date.parse("2015-03-29"), Date.today, nil, Date.today - 1.day, '%CURRENT_DATE%'] end end end shared_examples_for 'associated custom condition' do let(:instance) do described_class.new end let(:expected_key) do if defined?(key) key else raise ":key needs to be defined" end end describe '.key' do it 'is the expected key' do expect(described_class.key) .to eql(expected_key) end end describe '#key' do it 'is the expected key' do expect(instance.key) .to eql(expected_key) end end describe '#values' do it 'can be provided on initialization' do i = described_class.new(1) expect(i.values) .to eql [1] end it 'can be set and read' do instance.values = 1 expect(instance.values) .to eql [1] end it_behaves_like 'associated values transformation' end describe '#human_name' do it 'is the human_attribute_name' do expect(instance.human_name) .to eql(WorkPackage.human_attribute_name(expected_key)) end end describe '#validate' do let(:errors) do FactoryBot.build_stubbed(:custom_action).errors end it 'adds an error on conditions if values not from list of allowed values' do instance.values = [0] instance.validate(errors) expect(errors.symbols_for(:conditions)) .to eql [:inclusion] end end end shared_examples_for 'date custom action apply' do describe '#apply' do let(:work_package) { FactoryBot.build_stubbed(:stubbed_work_package) } it 'sets the daate to the action\'s value' do instance.values = [Date.today + 5.days] instance.apply(work_package) expect(work_package.send(key)) .to eql Date.today + 5.days end it 'sets the date to the current date if so specified' do instance.values = ['%CURRENT_DATE%'] instance.apply(work_package) expect(work_package.send(key)) .to eql Date.today end end end