diff --git a/app/components/types_de_champ_editor/conditions_component.rb b/app/components/types_de_champ_editor/conditions_component.rb index 8b792de2b..7d2324e49 100644 --- a/app/components/types_de_champ_editor/conditions_component.rb +++ b/app/components/types_de_champ_editor/conditions_component.rb @@ -105,7 +105,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent end def compatibles_operators_for_select(left) - case left.type + case left.type(@upper_tdcs) when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) [ [t('is', scope: 'logic'), Eq.name] @@ -135,7 +135,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent def right_operand_tag(left, right, row_index) right_invalid = !current_right_valid?(left, right) - case left.type + case left.type(@upper_tdcs) when :boolean booleans_for_select = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] @@ -156,7 +156,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent id: input_id_for('value', row_index) ) when :enum, :enums - enums_for_select = left.options + enums_for_select = left.options(@upper_tdcs) if right_invalid enums_for_select = empty_target_for_select + enums_for_select @@ -182,7 +182,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent end def current_right_valid?(left, right) - Logic.compatible_type?(left, right) + Logic.compatible_type?(left, right, @upper_tdcs) end def add_condition_tag diff --git a/app/components/types_de_champ_editor/conditions_errors_component.rb b/app/components/types_de_champ_editor/conditions_errors_component.rb index 4ad1ea313..9a5444651 100644 --- a/app/components/types_de_champ_editor/conditions_errors_component.rb +++ b/app/components/types_de_champ_editor/conditions_errors_component.rb @@ -6,10 +6,24 @@ class TypesDeChampEditor::ConditionsErrorsComponent < ApplicationComponent private def errors - @conditions - .flat_map { |condition| condition.errors(@upper_tdcs.map(&:stable_id)) } - .map { |error| humanize(error) } + errors = @conditions + .flat_map { |condition| condition.errors(@upper_tdcs) } .uniq + + # if a tdc is not available (has been removed for example) + # it causes a lot of errors (incompatible type for example) + # only the root cause is displayed + messages = if errors.include?({ type: :not_available }) + [t('not_available', scope: '.errors')] + else + errors.map { |error| humanize(error) } + end + + to_html_list(messages) + end + + def to_html_list(messages) + messages .map { |message| tag.li(message) } .then { |lis| tag.ul(lis.reduce(&:+)) } end @@ -48,7 +62,7 @@ class TypesDeChampEditor::ConditionsErrorsComponent < ApplicationComponent def render? @conditions - .filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? } + .filter { |condition| condition.errors(@upper_tdcs).present? } .present? end end diff --git a/app/controllers/administrateurs/conditions_controller.rb b/app/controllers/administrateurs/conditions_controller.rb index ba1e77cfa..4df461e0e 100644 --- a/app/controllers/administrateurs/conditions_controller.rb +++ b/app/controllers/administrateurs/conditions_controller.rb @@ -49,7 +49,7 @@ module Administrateurs end def condition_form - ConditionForm.new(condition_params) + ConditionForm.new(condition_params.merge({ upper_tdcs: @upper_tdcs })) end def retrieve_coordinate_and_uppers diff --git a/app/models/condition_form.rb b/app/models/condition_form.rb index faf04f444..ea103a8de 100644 --- a/app/models/condition_form.rb +++ b/app/models/condition_form.rb @@ -2,7 +2,7 @@ class ConditionForm include ActiveModel::Model include Logic - attr_accessor :top_operator_name, :rows + attr_accessor :top_operator_name, :rows, :upper_tdcs def to_condition case sub_conditions.count @@ -22,7 +22,7 @@ class ConditionForm end def change_champ(i) - sub_conditions[i] = Logic.ensure_compatibility_from_left(sub_conditions[i]) + sub_conditions[i] = Logic.ensure_compatibility_from_left(sub_conditions[i], upper_tdcs) self end @@ -39,7 +39,7 @@ class ConditionForm def row_to_condition(row) left = Logic.from_json(row[:targeted_champ]) - right = parse_value(left.type, row[:value]) + right = parse_value(left.type(upper_tdcs), row[:value]) Logic.class_from_name(row[:operator_name]).new(left, right) end diff --git a/app/models/logic.rb b/app/models/logic.rb index 3a8719a6e..5c3f1c25c 100644 --- a/app/models/logic.rb +++ b/app/models/logic.rb @@ -12,12 +12,12 @@ module Logic .find { |c| c.name == name } end - def self.ensure_compatibility_from_left(condition) + def self.ensure_compatibility_from_left(condition, type_de_champs) left = condition.left right = condition.right operator_class = condition.class - case [left.type, condition] + case [left.type(type_de_champs), condition] in [:boolean, _] operator_class = Eq in [:empty, _] @@ -31,14 +31,14 @@ module Logic in [:number, _] end - if !compatible_type?(left, right) - right = case left.type + if !compatible_type?(left, right, type_de_champs) + right = case left.type(type_de_champs) when :boolean Constant.new(true) when :empty Empty.new when :enum, :enums - Constant.new(left.options.first.second) + Constant.new(left.options(type_de_champs).first.second) when :number Constant.new(0) end @@ -47,8 +47,8 @@ module Logic operator_class.new(left, right) end - def self.compatible_type?(left, right) - case [left.type, right.type] + def self.compatible_type?(left, right, type_de_champs) + case [left.type(type_de_champs), right.type(type_de_champs)] in [a, ^a] # syntax for same type true in [:enum, :string] | [:enums, :string] diff --git a/app/models/logic/and.rb b/app/models/logic/and.rb index b5e17b25a..51537235f 100644 --- a/app/models/logic/and.rb +++ b/app/models/logic/and.rb @@ -7,5 +7,5 @@ class Logic::And < Logic::NAryOperator @operands.map { |operand| operand.compute(champs) }.all? end - def to_s = "(#{@operands.map(&:to_s).join(' && ')})" + def to_s(type_de_champs) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' && ')})" end diff --git a/app/models/logic/binary_operator.rb b/app/models/logic/binary_operator.rb index 7a73312c8..45ad7aa48 100644 --- a/app/models/logic/binary_operator.rb +++ b/app/models/logic/binary_operator.rb @@ -17,17 +17,17 @@ class Logic::BinaryOperator < Logic::Term self.new(Logic.from_h(h['left']), Logic.from_h(h['right'])) end - def errors(stable_ids = []) + def errors(type_de_champs = []) errors = [] - if @left.type != :number || @right.type != :number + if @left.type(type_de_champs) != :number || @right.type(type_de_champs) != :number errors << { type: :required_number, operator_name: self.class.name } end - errors + @left.errors(stable_ids) + @right.errors(stable_ids) + errors + @left.errors(type_de_champs) + @right.errors(type_de_champs) end - def type = :boolean + def type(type_de_champs = []) = :boolean def compute(champs = []) l = @left.compute(champs) @@ -36,7 +36,7 @@ class Logic::BinaryOperator < Logic::Term l&.send(operation, r) || false end - def to_s = "(#{@left} #{operation} #{@right})" + def to_s(type_de_champs) = "(#{@left.to_s(type_de_champs)} #{operation} #{@right.to_s(type_de_champs)})" def ==(other) self.class == other.class && diff --git a/app/models/logic/champ_value.rb b/app/models/logic/champ_value.rb index 610d7ee58..70db5a24b 100644 --- a/app/models/logic/champ_value.rb +++ b/app/models/logic/champ_value.rb @@ -29,7 +29,7 @@ class Logic::ChampValue < Logic::Term return nil if !targeted_champ.visible? return nil if targeted_champ.blank? - case type_de_champ.type_champ + case type_de_champ(champs.map(&:type_de_champ)).type_champ when MANAGED_TYPE_DE_CHAMP.fetch(:yes_no), MANAGED_TYPE_DE_CHAMP.fetch(:checkbox) targeted_champ.true? @@ -42,10 +42,10 @@ class Logic::ChampValue < Logic::Term end end - def to_s = type_de_champ&.libelle # TODO: gerer le cas ou un tdc est supprimé + def to_s(type_de_champs) = type_de_champ(type_de_champs)&.libelle # TODO: gerer le cas ou un tdc est supprimé - def type - case type_de_champ&.type_champ # TODO: gerer le cas ou un tdc est supprimé + def type(type_de_champs) + case type_de_champ(type_de_champs)&.type_champ # TODO: gerer le cas ou un tdc est supprimé when MANAGED_TYPE_DE_CHAMP.fetch(:yes_no), MANAGED_TYPE_DE_CHAMP.fetch(:checkbox) CHAMP_VALUE_TYPE.fetch(:boolean) @@ -60,8 +60,8 @@ class Logic::ChampValue < Logic::Term end end - def errors(stable_ids) - if !stable_ids.include?(stable_id) + def errors(type_de_champs) + if !type_de_champs.map(&:stable_id).include?(stable_id) [{ type: :not_available }] else [] @@ -83,9 +83,10 @@ class Logic::ChampValue < Logic::Term self.class == other.class && @stable_id == other.stable_id end - def options - opts = type_de_champ.drop_down_list_enabled_non_empty_options.map { |option| [option, option] } - if type_de_champ.drop_down_other? + def options(type_de_champs) + tdc = type_de_champ(type_de_champs) + opts = tdc.drop_down_list_enabled_non_empty_options.map { |option| [option, option] } + if tdc.drop_down_other? opts + [["Autre", Champs::DropDownListChamp::OTHER]] else opts @@ -94,8 +95,8 @@ class Logic::ChampValue < Logic::Term private - def type_de_champ - TypeDeChamp.find_by(stable_id: stable_id) + def type_de_champ(type_de_champs) + type_de_champs.find { |c| c.stable_id == stable_id } end def champ(champs) diff --git a/app/models/logic/constant.rb b/app/models/logic/constant.rb index ce27d77d8..3b72e7fbf 100644 --- a/app/models/logic/constant.rb +++ b/app/models/logic/constant.rb @@ -7,7 +7,7 @@ class Logic::Constant < Logic::Term def compute(_champs = nil) = @value - def to_s + def to_s(_type_de_champs = []) case @value when TrueClass I18n.t('utils.yes') @@ -18,7 +18,7 @@ class Logic::Constant < Logic::Term end end - def type + def type(_type_de_champs = []) case @value when TrueClass, FalseClass :boolean @@ -29,7 +29,7 @@ class Logic::Constant < Logic::Term end end - def errors(_stable_ids = nil) = [] + def errors(_type_de_champs = nil) = [] def to_h { diff --git a/app/models/logic/empty.rb b/app/models/logic/empty.rb index 08a92a101..d60e09442 100644 --- a/app/models/logic/empty.rb +++ b/app/models/logic/empty.rb @@ -1,9 +1,9 @@ class Logic::Empty < Logic::Term - def to_s = I18n.t('logic.empty') + def to_s(_type_de_champs = []) = I18n.t('logic.empty') - def type = :empty + def type(_type_de_champs = []) = :empty - def errors(_stable_ids = nil) = ['empty'] + def errors(_type_de_champs = []) = ['empty'] def to_h { diff --git a/app/models/logic/empty_operator.rb b/app/models/logic/empty_operator.rb index 0c9ab974d..318229836 100644 --- a/app/models/logic/empty_operator.rb +++ b/app/models/logic/empty_operator.rb @@ -1,9 +1,9 @@ class Logic::EmptyOperator < Logic::BinaryOperator - def to_s = "empty operator" + def to_s(_type_de_champs = []) = "empty operator" - def type = :empty + def type(_type_de_champs = []) = :empty - def errors(_stable_ids = nil) = [] + def errors(_type_de_champs = []) = [] def compute(_champs = []) true diff --git a/app/models/logic/eq.rb b/app/models/logic/eq.rb index d644f5450..0779be58e 100644 --- a/app/models/logic/eq.rb +++ b/app/models/logic/eq.rb @@ -1,20 +1,20 @@ class Logic::Eq < Logic::BinaryOperator def operation = :== - def errors(stable_ids = []) + def errors(type_de_champs = []) errors = [@left, @right] - .filter { |term| term.type == :unmanaged } + .filter { |term| term.type(type_de_champs) == :unmanaged } .map { |term| { type: :unmanaged, stable_id: term.stable_id } } - if !Logic.compatible_type?(@left, @right) + if !Logic.compatible_type?(@left, @right, type_de_champs) errors << { type: :incompatible, stable_id: @left.try(:stable_id), right: @right, operator_name: self.class.name } - elsif @left.type == :enum && - !left.options.map(&:second).include?(right.value) + elsif @left.type(type_de_champs) == :enum && + !left.options(type_de_champs).map(&:second).include?(right.value) errors << { type: :not_included, stable_id: @left.stable_id, @@ -22,7 +22,7 @@ class Logic::Eq < Logic::BinaryOperator } end - errors + @left.errors(stable_ids) + @right.errors(stable_ids) + errors + @left.errors(type_de_champs) + @right.errors(type_de_champs) end def ==(other) diff --git a/app/models/logic/include_operator.rb b/app/models/logic/include_operator.rb index 6ec906500..2e1f05c57 100644 --- a/app/models/logic/include_operator.rb +++ b/app/models/logic/include_operator.rb @@ -1,12 +1,12 @@ class Logic::IncludeOperator < Logic::BinaryOperator def operation = :include? - def errors(stable_ids = []) + def errors(type_de_champs = []) result = [] - if left_not_a_list? + if left_not_a_list?(type_de_champs) result << { type: :required_list } - elsif right_value_not_in_list? + elsif right_value_not_in_list?(type_de_champs) result << { type: :not_included, stable_id: @left.stable_id, @@ -14,16 +14,16 @@ class Logic::IncludeOperator < Logic::BinaryOperator } end - result + @left.errors(stable_ids) + @right.errors(stable_ids) + result + @left.errors(type_de_champs) + @right.errors(type_de_champs) end private - def left_not_a_list? - @left.type != :enums + def left_not_a_list?(type_de_champs) + @left.type(type_de_champs) != :enums end - def right_value_not_in_list? - !@left.options.map(&:second).include?(@right.value) + def right_value_not_in_list?(type_de_champs) + !@left.options(type_de_champs).map(&:second).include?(@right.value) end end diff --git a/app/models/logic/n_ary_operator.rb b/app/models/logic/n_ary_operator.rb index 8e274acb8..e6f723264 100644 --- a/app/models/logic/n_ary_operator.rb +++ b/app/models/logic/n_ary_operator.rb @@ -16,22 +16,22 @@ class Logic::NAryOperator < Logic::Term self.new(h['operands'].map { |operand_h| Logic.from_h(operand_h) }) end - def errors(stable_ids = []) + def errors(type_de_champs = []) errors = [] if @operands.empty? errors += ["opérateur '#{operator_name}' vide"] end - not_booleans = @operands.filter { |operand| operand.type != :boolean } + not_booleans = @operands.filter { |operand| operand.type(type_de_champs) != :boolean } if not_booleans.present? - errors += ["'#{operator_name}' ne contient pas que des booléens : #{not_booleans.map(&:to_s).join(', ')}"] + errors += ["'#{operator_name}' ne contient pas que des booléens : #{not_booleans.map { |o| o.to_s(type_de_champs) }.join(', ')}"] end - errors + @operands.flat_map { |operand| operand.errors(stable_ids) } + errors + @operands.flat_map { |operand| operand.errors(type_de_champs) } end - def type = :boolean + def type(_type_de_champs = []) = :boolean def ==(other) self.class == other.class && diff --git a/app/models/logic/or.rb b/app/models/logic/or.rb index 4f3a8b783..a0e2dfeae 100644 --- a/app/models/logic/or.rb +++ b/app/models/logic/or.rb @@ -7,5 +7,5 @@ class Logic::Or < Logic::NAryOperator @operands.map { |operand| operand.compute(champs) }.any? end - def to_s = "(#{@operands.map(&:to_s).join(' || ')})" + def to_s(type_de_champs = []) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' || ')})" end diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb index 086f43412..ec76bd947 100644 --- a/app/models/procedure_revision.rb +++ b/app/models/procedure_revision.rb @@ -317,7 +317,7 @@ class ProcedureRevision < ApplicationRecord changed = kept .map { |sid| [sid, from_h[sid], to_h[sid]] } .flat_map do |sid, from, to| - compare_type_de_champ(from.type_de_champ, to.type_de_champ) + compare_type_de_champ(from.type_de_champ, to.type_de_champ, from_coordinates, to_coordinates) .each { |h| h[:_position] = to_sids.index(sid) } end @@ -327,7 +327,7 @@ class ProcedureRevision < ApplicationRecord end end - def compare_type_de_champ(from_type_de_champ, to_type_de_champ) + def compare_type_de_champ(from_type_de_champ, to_type_de_champ, from_coordinates, to_coordinates) changes = [] if from_type_de_champ.type_champ != to_type_de_champ.type_champ changes << { @@ -385,8 +385,8 @@ class ProcedureRevision < ApplicationRecord attribute: :condition, label: from_type_de_champ.libelle, private: from_type_de_champ.private?, - from: from_type_de_champ.condition&.to_s, - to: to_type_de_champ.condition&.to_s, + from: from_type_de_champ.condition&.to_s(from_coordinates.map(&:type_de_champ)), + to: to_type_de_champ.condition&.to_s(to_coordinates.map(&:type_de_champ)), stable_id: from_type_de_champ.stable_id } end @@ -479,12 +479,12 @@ class ProcedureRevision < ApplicationRecord end def conditions_are_valid? - stable_ids = types_de_champ_public.map(&:stable_id) + public_tdcs = types_de_champ_public.to_a - types_de_champ_public + public_tdcs .map.with_index .filter_map { |tdc, i| tdc.condition.present? ? [tdc, i] : nil } - .map { |tdc, i| [tdc, tdc.condition.errors(stable_ids.take(i))] } + .map { |tdc, i| [tdc, tdc.condition.errors(public_tdcs.take(i))] } .filter { |_tdc, errors| errors.present? } .each { |tdc, message| errors.add(:condition, message, type_de_champ: tdc) } end diff --git a/spec/controllers/administrateurs/conditions_controller_spec.rb b/spec/controllers/administrateurs/conditions_controller_spec.rb index ddedfdddc..2b34060ab 100644 --- a/spec/controllers/administrateurs/conditions_controller_spec.rb +++ b/spec/controllers/administrateurs/conditions_controller_spec.rb @@ -1,16 +1,20 @@ describe Administrateurs::ConditionsController, type: :controller do include Logic - let(:procedure) { create(:procedure, :with_type_de_champ, types_de_champ_count: 2) } + let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :integer_number }] * 3) } let(:first_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:second_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:third_coordinate) { procedure.draft_revision.revision_types_de_champ.first } + let(:first_tdc) { procedure.draft_revision.types_de_champ.first } let(:second_tdc) { procedure.draft_revision.types_de_champ.second } + let(:third_tdc) { procedure.draft_revision.types_de_champ.third } before { sign_in(procedure.administrateurs.first.user) } let(:default_params) do { procedure_id: procedure.id, - stable_id: second_tdc.stable_id + stable_id: third_tdc.stable_id } end @@ -23,7 +27,7 @@ describe Administrateurs::ConditionsController, type: :controller do { rows: [ { - targeted_champ: champ_value(1).to_json, + targeted_champ: champ_value(first_tdc.stable_id).to_json, operator_name: Logic::Eq.name, value: '2' } @@ -32,9 +36,9 @@ describe Administrateurs::ConditionsController, type: :controller do end it do - expect(second_tdc.reload.condition).to eq(ds_eq(champ_value(1), constant('2'))) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ]) + expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(first_tdc.stable_id), constant(2))) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end @@ -42,9 +46,9 @@ describe Administrateurs::ConditionsController, type: :controller do before { post :add_row, params: default_params, format: :turbo_stream } it do - expect(second_tdc.reload.condition).to eq(empty_operator(empty, empty)) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ]) + expect(third_tdc.reload.condition).to eq(empty_operator(empty, empty)) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end @@ -66,9 +70,9 @@ describe Administrateurs::ConditionsController, type: :controller do end it do - expect(second_tdc.reload.condition).to eq(nil) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ]) + expect(third_tdc.reload.condition).to eq(nil) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end @@ -79,15 +83,13 @@ describe Administrateurs::ConditionsController, type: :controller do end it do - expect(second_tdc.reload.condition).to eq(nil) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ]) + expect(third_tdc.reload.condition).to eq(nil) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end describe '#change_targeted_champ' do - let!(:number_tdc) { create(:type_de_champ_integer_number) } - before do second_tdc.update(condition: empty_operator(empty, empty)) patch :change_targeted_champ, params: params, format: :turbo_stream @@ -99,7 +101,7 @@ describe Administrateurs::ConditionsController, type: :controller do { rows: [ { - targeted_champ: champ_value(number_tdc.stable_id).to_json, + targeted_champ: champ_value(second_tdc.stable_id).to_json, operator_name: Logic::EmptyOperator.name, value: empty.to_json } @@ -108,9 +110,9 @@ describe Administrateurs::ConditionsController, type: :controller do end it do - expect(second_tdc.reload.condition).to eq(ds_eq(champ_value(number_tdc.stable_id), constant(0))) - expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc)) - expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ]) + expect(third_tdc.reload.condition).to eq(ds_eq(champ_value(second_tdc.stable_id), constant(0))) + expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(third_tdc)) + expect(assigns(:upper_tdcs)).to eq([first_tdc, second_tdc]) end end end diff --git a/spec/models/logic/and_spec.rb b/spec/models/logic/and_spec.rb index 23bcb6abb..67f319acb 100644 --- a/spec/models/logic/and_spec.rb +++ b/spec/models/logic/and_spec.rb @@ -8,7 +8,7 @@ describe Logic::And do describe '#to_s' do it do - expect(and_from([true, false, true]).to_s).to eq "(Oui && Non && Oui)" + expect(and_from([true, false, true]).to_s([])).to eq "(Oui && Non && Oui)" end end diff --git a/spec/models/logic/binary_operator_spec.rb b/spec/models/logic/binary_operator_spec.rb index ebd791d08..28e45d041 100644 --- a/spec/models/logic/binary_operator_spec.rb +++ b/spec/models/logic/binary_operator_spec.rb @@ -7,7 +7,7 @@ describe Logic::BinaryOperator do end describe '#to_s' do - it { expect(two_greater_than_one.to_s).to eq('(2 > 1)') } + it { expect(two_greater_than_one.to_s([])).to eq('(2 > 1)') } end describe '#==' do diff --git a/spec/models/logic/champ_value_spec.rb b/spec/models/logic/champ_value_spec.rb index 436e7e300..ff102b252 100644 --- a/spec/models/logic/champ_value_spec.rb +++ b/spec/models/logic/champ_value_spec.rb @@ -7,7 +7,7 @@ describe Logic::ChampValue do let(:value) { 'true' } let(:champ) { create(:champ_yes_no, value: value) } - it { expect(champ_value(champ.stable_id).type).to eq(:boolean) } + it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } context 'with true value' do it { is_expected.to be(true) } @@ -31,7 +31,7 @@ describe Logic::ChampValue do context 'integer tdc' do let(:champ) { create(:champ_integer_number, value: '42') } - it { expect(champ_value(champ.stable_id).type).to eq(:number) } + it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { is_expected.to eq(42) } context 'with a blank value' do @@ -44,22 +44,22 @@ describe Logic::ChampValue do context 'decimal tdc' do let(:champ) { create(:champ_decimal_number, value: '42.01') } - it { expect(champ_value(champ.stable_id).type).to eq(:number) } + it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { is_expected.to eq(42.01) } end context 'dropdown tdc' do let(:champ) { create(:champ_drop_down_list, value: 'val1') } - it { expect(champ_value(champ.stable_id).type).to eq(:enum) } + it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:enum) } it { is_expected.to eq('val1') } - it { expect(champ_value(champ.stable_id).options).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"]]) } + it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"]]) } context 'with other enabled' do let(:champ) { create(:champ_drop_down_list, value: 'val1', other: true) } it { is_expected.to eq('val1') } - it { expect(champ_value(champ.stable_id).options).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"], ["Autre", "__other__"]]) } + it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"], ["Autre", "__other__"]]) } end context 'with other filled' do @@ -72,14 +72,39 @@ describe Logic::ChampValue do context 'checkbox tdc' do let(:champ) { create(:champ_checkbox, value: 'on') } - it { expect(champ_value(champ.stable_id).type).to eq(:boolean) } + it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } it { is_expected.to eq(true) } end describe 'errors' do let(:champ) { create(:champ) } - it { expect(champ_value(champ.stable_id).errors([champ.stable_id])).to be_empty } - it { expect(champ_value(champ.stable_id).errors(['other stable ids'])).to eq([{ type: :not_available }]) } + it { expect(champ_value(champ.stable_id).errors([champ.type_de_champ])).to be_empty } + it { expect(champ_value(champ.stable_id).errors([])).to eq([{ type: :not_available }]) } + end + + context 'with multiple revision' do + let(:options) { ['revision_1'] } + let(:procedure) do + create(:procedure, :published, :for_individual, types_de_champ_public: [{ type: :drop_down_list, libelle: 'dropdown', options: options }]) + end + let(:drop_down_r1) { procedure.published_revision.types_de_champ_public.first } + let(:stable_id) { drop_down_r1.stable_id } + + it { expect(champ_value(stable_id).options([drop_down_r1])).to match_array([["revision_1", "revision_1"]]) } + + context 'with a new revision' do + let(:drop_down_r2) { procedure.draft_revision.types_de_champ_public.first } + + before do + tdc = procedure.draft_revision.find_and_ensure_exclusive_use(stable_id) + tdc.drop_down_options = ['revision_2'] + tdc.save! + end + + it do + expect(champ_value(stable_id).options([drop_down_r2])).to match_array([["revision_2", "revision_2"]]) + end + end end end diff --git a/spec/models/logic/include_operator_spec.rb b/spec/models/logic/include_operator_spec.rb index 3583a720b..5697c1f2d 100644 --- a/spec/models/logic/include_operator_spec.rb +++ b/spec/models/logic/include_operator_spec.rb @@ -9,7 +9,7 @@ describe Logic::IncludeOperator do end describe '#errors' do - it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).errors([champ.stable_id])).to be_empty } + it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).errors([champ.type_de_champ])).to be_empty } it do expected = { right: constant('something else'), @@ -17,10 +17,10 @@ describe Logic::IncludeOperator do type: :not_included } - expect(ds_include(champ_value(champ.stable_id), constant('something else')).errors([champ.stable_id])).to eq([expected]) + expect(ds_include(champ_value(champ.stable_id), constant('something else')).errors([champ.type_de_champ])).to eq([expected]) end - it { expect(ds_include(constant(1), constant('val1')).errors).to eq([{ type: :required_list }]) } + it { expect(ds_include(constant(1), constant('val1')).errors([])).to eq([{ type: :required_list }]) } end describe '#==' do diff --git a/spec/models/logic_spec.rb b/spec/models/logic_spec.rb index 66dbab3a7..74fb8142b 100644 --- a/spec/models/logic_spec.rb +++ b/spec/models/logic_spec.rb @@ -16,7 +16,8 @@ describe Logic do end describe '.ensure_compatibility_from_left' do - subject { Logic.ensure_compatibility_from_left(condition) } + let(:type_de_champs) { [] } + subject { Logic.ensure_compatibility_from_left(condition, type_de_champs) } context 'when it s fine' do let(:condition) { greater_than(constant(1), constant(1)) } @@ -44,31 +45,33 @@ describe Logic do context 'when dropdown empty operator true' do let(:drop_down) { create(:type_de_champ_drop_down_list) } + let(:type_de_champs) { [drop_down] } let(:first_option) { drop_down.drop_down_list_enabled_non_empty_options.first } - let(:condition) { empty_operator(champ_value(drop_down), constant(true)) } + let(:condition) { empty_operator(champ_value(drop_down.stable_id), constant(true)) } - it { is_expected.to eq(ds_eq(champ_value(drop_down), constant(first_option))) } + it { is_expected.to eq(ds_eq(champ_value(drop_down.stable_id), constant(first_option))) } end context 'when multiple dropdown empty operator true' do let(:multiple_drop_down) { create(:type_de_champ_multiple_drop_down_list) } + let(:type_de_champs) { [multiple_drop_down] } let(:first_option) { multiple_drop_down.drop_down_list_enabled_non_empty_options.first } - let(:condition) { empty_operator(champ_value(multiple_drop_down), constant(true)) } + let(:condition) { empty_operator(champ_value(multiple_drop_down.stable_id), constant(true)) } - it { is_expected.to eq(ds_include(champ_value(multiple_drop_down), constant(first_option))) } + it { is_expected.to eq(ds_include(champ_value(multiple_drop_down.stable_id), constant(first_option))) } end end describe '.compatible_type?' do - it { expect(Logic.compatible_type?(constant(true), constant(true))).to be true } - it { expect(Logic.compatible_type?(constant(1), constant(true))).to be false } + it { expect(Logic.compatible_type?(constant(true), constant(true), [])).to be true } + it { expect(Logic.compatible_type?(constant(1), constant(true), [])).to be false } context 'with a dropdown' do let(:drop_down) { create(:type_de_champ_drop_down_list) } let(:first_option) { drop_down.drop_down_list_enabled_non_empty_options.first } it do - expect(Logic.compatible_type?(champ_value(drop_down.stable_id), constant('a'))).to be true + expect(Logic.compatible_type?(champ_value(drop_down.stable_id), constant('a'), [drop_down])).to be true end end end