From 3881b47e26911f40cf0dfb154870713bd6a1a490 Mon Sep 17 00:00:00 2001 From: ulferts Date: Mon, 26 Mar 2018 10:33:25 +0200 Subject: [PATCH] add parent filter to wp query (#6235) [ci skip] --- app/models/queries/work_packages.rb | 1 + .../filter/filter_for_wp_mixing.rb | 75 +++++ .../queries/work_packages/filter/id_filter.rb | 46 +--- .../work_packages/filter/parent_filter.rb | 47 ++++ .../work_packages/filter/type_filter.rb | 1 + app/models/work_package.rb | 6 + .../wp-fast-table/wp-table-filters.ts | 4 +- ...k_package_filter_dependency_representer.rb | 59 ++++ .../id_filter_dependency_representer.rb | 22 +- .../parent_filter_dependency_representer.rb | 39 +++ ...rent_filter_dependency_representer_spec.rb | 133 +++++++++ .../work_packages/filter/id_filter_spec.rb | 16 +- .../filter/parent_filter_spec.rb | 259 ++++++++++++++++++ 13 files changed, 640 insertions(+), 68 deletions(-) create mode 100644 app/models/queries/work_packages/filter/filter_for_wp_mixing.rb create mode 100644 app/models/queries/work_packages/filter/parent_filter.rb create mode 100644 lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb create mode 100644 lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb create mode 100644 spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb create mode 100644 spec/models/queries/work_packages/filter/parent_filter_spec.rb diff --git a/app/models/queries/work_packages.rb b/app/models/queries/work_packages.rb index 8331b80b72..09f558c55e 100644 --- a/app/models/queries/work_packages.rb +++ b/app/models/queries/work_packages.rb @@ -57,6 +57,7 @@ module Queries::WorkPackages register.filter Query, filters_module::UpdatedAtFilter register.filter Query, filters_module::VersionFilter register.filter Query, filters_module::WatcherFilter + register.filter Query, filters_module::ParentFilter columns_module = Queries::WorkPackages::Columns diff --git a/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb b/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb new file mode 100644 index 0000000000..3f4fbf5075 --- /dev/null +++ b/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb @@ -0,0 +1,75 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +module Queries::WorkPackages::Filter::FilterForWpMixin + def type + :list + end + + def allowed_values + raise NotImplementedError, 'There would be too many candidates' + end + + def value_objects + scope.find(values) + end + + def allowed_objects + raise NotImplementedError, 'There would be too many candidates' + end + + def available? + scope.exists? + end + + def ar_object_filter? + true + end + + def allowed_values_subset + scope.where(id: values).pluck(:id).map(&:to_s) + end + + private + + def scope + if context.project + WorkPackage + .visible + .for_projects(context.project.self_and_descendants) + else + WorkPackage.visible + end + end + + def type_strategy + @type_strategy ||= Queries::Filters::Strategies::HugeList.new(self) + end +end diff --git a/app/models/queries/work_packages/filter/id_filter.rb b/app/models/queries/work_packages/filter/id_filter.rb index f9b163ef96..8337525391 100644 --- a/app/models/queries/work_packages/filter/id_filter.rb +++ b/app/models/queries/work_packages/filter/id_filter.rb @@ -28,48 +28,10 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -class Queries::WorkPackages::Filter::IdFilter < Queries::WorkPackages::Filter::WorkPackageFilter - def type - :list - end +require_relative './filter_for_wp_mixing' - def allowed_values - raise NotImplementedError, 'There would be too many candidates' - end +class Queries::WorkPackages::Filter::IdFilter < + Queries::WorkPackages::Filter::WorkPackageFilter - def value_objects - raise NotImplementedError, 'There would be too many candidates' - end - - def allowed_objects - raise NotImplementedError, 'There would be too many candidates' - end - - def available? - scope.exists? - end - - def ar_object_filter? - true - end - - def allowed_values_subset - scope.where(id: values).pluck(:id).map(&:to_s) - end - - private - - def scope - if context.project - WorkPackage - .visible - .for_projects(context.project.self_and_descendants) - else - WorkPackage.visible - end - end - - def type_strategy - @type_strategy ||= Queries::Filters::Strategies::HugeList.new(self) - end + include ::Queries::WorkPackages::Filter::FilterForWpMixin end diff --git a/app/models/queries/work_packages/filter/parent_filter.rb b/app/models/queries/work_packages/filter/parent_filter.rb new file mode 100644 index 0000000000..47c1f6d4b8 --- /dev/null +++ b/app/models/queries/work_packages/filter/parent_filter.rb @@ -0,0 +1,47 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require_relative './filter_for_wp_mixing' + +class Queries::WorkPackages::Filter::ParentFilter < + Queries::WorkPackages::Filter::WorkPackageFilter + + include ::Queries::WorkPackages::Filter::FilterForWpMixin + + def includes + :parent_relation + end + + def where + operator_strategy.sql_for_field(values, + Relation.table_name, + 'from_id') + end +end diff --git a/app/models/queries/work_packages/filter/type_filter.rb b/app/models/queries/work_packages/filter/type_filter.rb index fba3785f64..a64b914812 100644 --- a/app/models/queries/work_packages/filter/type_filter.rb +++ b/app/models/queries/work_packages/filter/type_filter.rb @@ -1,4 +1,5 @@ #-- encoding: UTF-8 + #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2018 the OpenProject Foundation (OPF) diff --git a/app/models/work_package.rb b/app/models/work_package.rb index ea178b8d39..7b9a62d33c 100644 --- a/app/models/work_package.rb +++ b/app/models/work_package.rb @@ -299,6 +299,12 @@ class WorkPackage < ActiveRecord::Base project && type ? (project.all_work_package_custom_fields & type.custom_fields) : [] end + # aliasing subject to name + # using :alias is not possible as AR will add the subject method later + def name + subject + end + def status_id=(sid) self.status = nil write_attribute(:status_id, sid) diff --git a/frontend/app/components/wp-fast-table/wp-table-filters.ts b/frontend/app/components/wp-fast-table/wp-table-filters.ts index 88b69d7f6c..d457f9df37 100644 --- a/frontend/app/components/wp-fast-table/wp-table-filters.ts +++ b/frontend/app/components/wp-fast-table/wp-table-filters.ts @@ -78,8 +78,8 @@ export class WorkPackageTableFilters extends WorkPackageTableBaseState (schema.filter.allowedValues as QueryFilterResource[])[0]); - // We do not use the id filter as of now as we do not have adequate + // We do not use the filters id and parent as of now as we do not have adequate // means to select the values. - return _.filter(availableFilters, filter => filter.id !== 'id'); + return _.filter(availableFilters, filter => filter.id !== 'id' && filter.id !== 'parent'); } } diff --git a/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb new file mode 100644 index 0000000000..910f12e8a2 --- /dev/null +++ b/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb @@ -0,0 +1,59 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +module API + module V3 + module Queries + module Schemas + class ByWorkPackageFilterDependencyRepresenter < + FilterDependencyRepresenter + + def json_cache_key + super + (filter.project.present? ? [filter.project.id] : []) + end + + def href_callback + if filter.project + api_v3_paths.work_packages_by_project(filter.project.id) + else + api_v3_paths.work_packages + end + end + + private + + def type + '[]WorkPackage' + end + end + end + end + end +end diff --git a/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb index 7ca259f011..6e015550cc 100644 --- a/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb +++ b/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb @@ -32,27 +32,7 @@ module API module V3 module Queries module Schemas - class IdFilterDependencyRepresenter < - FilterDependencyRepresenter - - def json_cache_key - super + (filter.project.present? ? [filter.project.id] : []) - end - - def href_callback - if filter.project - api_v3_paths.work_packages_by_project(filter.project.id) - else - api_v3_paths.work_packages - end - end - - private - - def type - '[]WorkPackage' - end - end + class IdFilterDependencyRepresenter < ByWorkPackageFilterDependencyRepresenter; end end end end diff --git a/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb new file mode 100644 index 0000000000..dd3109decb --- /dev/null +++ b/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb @@ -0,0 +1,39 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +module API + module V3 + module Queries + module Schemas + class ParentFilterDependencyRepresenter < ByWorkPackageFilterDependencyRepresenter; end + end + end + end +end diff --git a/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb new file mode 100644 index 0000000000..a93ee60c17 --- /dev/null +++ b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb @@ -0,0 +1,133 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe ::API::V3::Queries::Schemas::ParentFilterDependencyRepresenter, clear_cache: true do + include ::API::V3::Utilities::PathHelper + + let(:project) { FactoryGirl.build_stubbed(:project) } + let(:query) { FactoryGirl.build_stubbed(:query, project: project) } + let(:filter) { Queries::WorkPackages::Filter::ParentFilter.create!(context: query) } + let(:form_embedded) { false } + + let(:instance) do + described_class.new(filter, + operator, + form_embedded: form_embedded) + end + + subject(:generated) { instance.to_json } + + context 'generation' do + context 'properties' do + describe 'values' do + context 'within project' do + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } + let(:href) { api_v3_paths.work_packages_by_project(project.id) } + + context "for operator 'Queries::Operators::Equals'" do + let(:operator) { Queries::Operators::Equals } + + it_behaves_like 'filter dependency with allowed link' + end + + context "for operator 'Queries::Operators::NotEquals'" do + let(:operator) { Queries::Operators::NotEquals } + + it_behaves_like 'filter dependency with allowed link' + end + end + + context 'outside of a project' do + let(:project) { nil } + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } + let(:href) { api_v3_paths.work_packages } + + context "for operator 'Queries::Operators::Equals'" do + let(:operator) { Queries::Operators::Equals } + + it_behaves_like 'filter dependency with allowed link' + end + + context "for operator 'Queries::Operators::NotEquals'" do + let(:operator) { Queries::Operators::NotEquals } + + it_behaves_like 'filter dependency with allowed link' + end + end + end + end + + describe 'caching' do + let(:operator) { Queries::Operators::Equals } + let(:other_project) { FactoryGirl.build_stubbed(:project) } + + before do + # fill the cache + instance.to_json + end + + it 'is cached' do + expect(instance) + .not_to receive(:to_hash) + + instance.to_json + end + + it 'busts the cache on a different operator' do + instance.send(:operator=, Queries::Operators::NotEquals) + + expect(instance) + .to receive(:to_hash) + + instance.to_json + end + + it 'busts the cache on a different project' do + query.project = other_project + + expect(instance) + .to receive(:to_hash) + + instance.to_json + end + + it 'busts the cache on changes to the locale' do + expect(instance) + .to receive(:to_hash) + + I18n.with_locale(:de) do + instance.to_json + end + end + end + end +end diff --git a/spec/models/queries/work_packages/filter/id_filter_spec.rb b/spec/models/queries/work_packages/filter/id_filter_spec.rb index 4afbcbf374..322c051082 100644 --- a/spec/models/queries/work_packages/filter/id_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/id_filter_spec.rb @@ -57,7 +57,7 @@ describe Queries::WorkPackages::Filter::IdFilter, type: :model do expect(instance).to be_available end - it 'is fals if no work package exists/ is visible' do + it 'is false if no work package exists/ is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :exists?) .with(no_args) @@ -105,8 +105,18 @@ describe Queries::WorkPackages::Filter::IdFilter, type: :model do end describe '#value_object' do - it 'raises an error' do - expect { instance.value_objects }.to raise_error NotImplementedError + let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) } + + it 'returns the work package for the values' do + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :find) + .with(no_args) + .with(project) + .with(instance.values) + .and_return([visible_wp]) + + expect(instance.value_objects) + .to match_array [visible_wp] end end diff --git a/spec/models/queries/work_packages/filter/parent_filter_spec.rb b/spec/models/queries/work_packages/filter/parent_filter_spec.rb new file mode 100644 index 0000000000..b3beb2c480 --- /dev/null +++ b/spec/models/queries/work_packages/filter/parent_filter_spec.rb @@ -0,0 +1,259 @@ +#-- encoding: UTF-8 + +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) +# +# 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-2017 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 docs/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe Queries::WorkPackages::Filter::ParentFilter, type: :model do + let(:project) { FactoryGirl.build_stubbed(:project) } + let(:query) do + FactoryGirl.build_stubbed(:query, project: project) + end + + it_behaves_like 'basic query filter' do + let(:class_key) { :parent } + let(:type) { :list } + + before do + instance.context = query + end + + describe '#available?' do + context 'within a project' do + it 'is true if any work package exists and is visible' do + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :exists?) + .with(no_args) + .with(project) + .with(no_args) + .and_return true + + expect(instance).to be_available + end + + it 'is false if no work package exists/ is visible' do + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :exists?) + .with(no_args) + .with(project) + .with(no_args) + .and_return false + + expect(instance).not_to be_available + end + end + + context 'outside of a project' do + let(:project) { nil } + + it 'is true if any work package exists and is visible' do + allow(WorkPackage) + .to receive_message_chain(:visible, :exists?) + .with(no_args) + .and_return true + + expect(instance).to be_available + end + + it 'is false if no work package exists/ is visible' do + allow(WorkPackage) + .to receive_message_chain(:visible, :exists?) + .with(no_args) + .and_return false + + expect(instance).not_to be_available + end + end + end + + describe '#ar_object_filter?' do + it 'is true' do + expect(instance).to be_ar_object_filter + end + end + + describe '#allowed_values' do + it 'raises an error' do + expect { instance.allowed_values }.to raise_error NotImplementedError + end + end + + describe '#value_object' do + let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) } + + it 'returns the work package for the values' do + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :find) + .with(no_args) + .with(project) + .with(instance.values) + .and_return([visible_wp]) + + expect(instance.value_objects) + .to match_array [visible_wp] + end + end + + describe '#allowed_objects' do + it 'raises an error' do + expect { instance.allowed_objects }.to raise_error NotImplementedError + end + end + + describe '#valid_values!' do + let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) } + let(:invisible_wp) { FactoryGirl.build_stubbed(:work_package) } + + context 'within a project' do + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] + + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :where, :pluck) + .with(no_args) + .with(project) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + instance.valid_values! + + expect(instance.values) + .to match_array [visible_wp.id.to_s] + end + end + + context 'outside of a project' do + let(:project) { nil } + + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] + + allow(WorkPackage) + .to receive_message_chain(:visible, :where, :pluck) + .with(no_args) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + instance.valid_values! + + expect(instance.values) + .to match_array [visible_wp.id.to_s] + end + end + end + + describe '#validate' do + let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) } + let(:invisible_wp) { FactoryGirl.build_stubbed(:work_package) } + + context 'within a project' do + it 'is valid if only visible wps are values' do + instance.values = [visible_wp.id.to_s] + + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :where, :pluck) + .with(no_args) + .with(project) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + expect(instance).to be_valid + end + + it 'is invalid if invisible wps are values' do + instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] + + allow(WorkPackage) + .to receive_message_chain(:visible, :for_projects, :where, :pluck) + .with(no_args) + .with(project) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + expect(instance).not_to be_valid + end + end + + context 'outside of a project' do + let(:project) { nil } + + it 'is valid if only visible wps are values' do + instance.values = [visible_wp.id.to_s] + + allow(WorkPackage) + .to receive_message_chain(:visible, :where, :pluck) + .with(no_args) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + expect(instance).to be_valid + end + + it 'is invalid if invisible wps are values' do + instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] + + allow(WorkPackage) + .to receive_message_chain(:visible, :where, :pluck) + .with(no_args) + .with(id: instance.values) + .with(:id) + .and_return([visible_wp.id]) + + expect(instance).not_to be_valid + end + end + end + + describe '#where and #includes' do + let(:parent) { FactoryGirl.create(:work_package) } + let(:visible_wp) { FactoryGirl.create(:work_package, parent: parent) } + + before do + visible_wp + instance.values = [parent.id.to_s] + instance.operator = '=' + end + + it 'filters' do + scope = WorkPackage + .references(instance.includes) + .includes(instance.includes) + .where(instance.where) + + expect(scope) + .to match_array [visible_wp] + end + end + end +end