Files

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

292 lines
8.4 KiB
Ruby
Raw Permalink Normal View History

2024-01-23 16:48:37 +01:00
# frozen_string_literal: true
# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
2024-01-23 16:48:37 +01:00
#
# 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.
# ++
require "spec_helper"
RSpec.describe Queries::ParamsParser, type: :model do
let(:params) do
{}
end
subject { described_class.parse(params.with_indifferent_access) }
describe ".parse" do
context "without any params" do
it "returns an empty array" do
expect(subject)
.to be_empty
end
end
context "with a single filter with a single value" do
let(:params) do
{
filters: "active = t"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: ["t"] })
end
end
context "with a single filter with multiple values having single quotes" do
let(:params) do
{
filters: "active = ['t', 'f']"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] })
end
end
context "with a single filter with multiple values having double quotes" do
let(:params) do
{
filters: "active = [\"t\", \"f\"]"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] })
end
end
2024-01-26 13:57:15 +01:00
context "with a single filter with a single value with , and &" do
2024-01-23 16:48:37 +01:00
let(:params) do
{
2024-01-26 13:57:15 +01:00
filters: "active = something, or another thing & something else"
2024-01-23 16:48:37 +01:00
}
end
it "returns the parsed filter" do
2024-01-26 13:57:15 +01:00
# This returns invalid filters but they will then be marked as invalid
2024-01-23 16:48:37 +01:00
expect(subject[:filters])
2024-01-26 13:57:15 +01:00
.to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing "] },
{ attribute: "something", operator: "else", values: [""] })
2024-01-23 16:48:37 +01:00
end
end
context 'with a single filter with a single value with " (escaped)' do
let(:params) do
{
filters: 'active = "something, or another thing \" something else"'
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing \" something else"] })
end
end
2024-01-26 13:57:15 +01:00
context "with a single filter with a single value with ' (escaped)" do
let(:params) do
{
filters: "active = 'something, or another thing \\' something else'"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing ' something else"] })
end
end
context "with a single filter with no value" do
2024-01-23 16:48:37 +01:00
let(:params) do
{
filters: "cf_512 !* "
}
end
it "returns the parsed filter" do
expect(subject[:filters])
2024-01-26 13:57:15 +01:00
.to contain_exactly({ attribute: "cf_512", operator: "!*", values: [""] })
end
end
context "with multiple filters with the first having no value" do
let(:params) do
{
filters: "active !* & id = \"1\""
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "!*", values: [] },
{ attribute: "id", operator: "=", values: ["1"] })
end
end
context "with multiple filters with ampersand as a filter value" do
let(:params) do
{
filters: "active = \"t\" & name_and_identifier ~ \"abc & def\""
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: ["t"] },
{ attribute: "name_and_identifier", operator: "~", values: ["abc & def"] })
end
end
context "with a corrupt filter only having a key" do
let(:params) do
{
filters: "active"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "", values: [""] })
end
end
context "with a corrupt filter having opening braces but no closing ones" do
let(:params) do
{
filters: "active = [\"t\", \"f\""
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] })
end
end
context "with a corrupt filter having opening double quotes but no closing ones" do
let(:params) do
{
filters: 'active = "t'
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[t] })
end
end
context "with a corrupt filter having opening single quotes but no closing ones" do
let(:params) do
{
filters: "active = 't"
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[t] })
2024-01-23 16:48:37 +01:00
end
end
context "with an old (APIv3) style filter" do
let(:params) do
{
filters: JSON.dump([{ active: { operator: "=", values: ["f"] } },
{ cf_32: { operator: "=", values: ["63"] } }, # rubocop:disable Naming/VariableNumber
{ cf_34: { operator: "=", values: ["2006"] } }]) # rubocop:disable Naming/VariableNumber
}
end
it "returns the parsed filter" do
expect(subject[:filters])
.to contain_exactly({ attribute: "active", operator: "=", values: %w[f] },
{ attribute: "cf_32", operator: "=", values: %w[63] },
{ attribute: "cf_34", operator: "=", values: %w[2006] })
end
end
2024-01-23 16:48:37 +01:00
context "with sortBy with a single value" do
let(:params) do
{
sortBy: JSON.dump([%w[name asc]])
}
end
it "returns the parsed filter" do
expect(subject[:orders])
.to eql [{ attribute: "name", direction: "asc" }]
end
end
context "with sortBy with a multiple value" do
let(:params) do
{
sortBy: JSON.dump([%w[name asc], %w[created_at desc]])
}
end
it "returns the parsed filter" do
expect(subject[:orders])
.to eql [{ attribute: "name", direction: "asc" }, { attribute: "created_at", direction: "desc" }]
end
end
context "with an invalid sortBy" do
let(:params) do
{
sortBy: "[sjfkdsjfkd}"
}
end
it "returns an invalid sort order" do
expect(subject[:orders])
.to eql [{ attribute: "invalid", direction: "asc" }]
end
end
2024-02-01 18:02:49 +01:00
context "with multiple columns" do
let(:params) do
{
columns: "name cf_1 project_status"
}
end
it "returns an invalid sort order" do
2024-02-16 09:25:24 +01:00
expect(subject[:selects])
2024-02-01 18:02:49 +01:00
.to eql %w[name cf_1 project_status]
end
end
2024-01-23 16:48:37 +01:00
end
end