summaryrefslogtreecommitdiffstats
path: root/xt/lib/Bugzilla/Test/Search
diff options
context:
space:
mode:
authorDavid Lawrence <dkl@mozilla.com>2016-02-26 18:57:55 +0100
committerDavid Lawrence <dkl@mozilla.com>2016-02-26 18:57:55 +0100
commit9b6ec1f545da1cc4088ddf9cc117747954e58e65 (patch)
tree6cc3eb342a740b795052e587756f6c33438b772a /xt/lib/Bugzilla/Test/Search
parent6f70920f2d2bb038a371e3cb3debff44f7001fa8 (diff)
downloadbugzilla-9b6ec1f545da1cc4088ddf9cc117747954e58e65.tar.gz
bugzilla-9b6ec1f545da1cc4088ddf9cc117747954e58e65.tar.xz
Bug 1069799 - move the QA repository into the main repository
r=LpSolit
Diffstat (limited to 'xt/lib/Bugzilla/Test/Search')
-rw-r--r--xt/lib/Bugzilla/Test/Search/AndTest.pm52
-rw-r--r--xt/lib/Bugzilla/Test/Search/Constants.pm1203
-rw-r--r--xt/lib/Bugzilla/Test/Search/CustomTest.pm101
-rw-r--r--xt/lib/Bugzilla/Test/Search/FieldTest.pm617
-rw-r--r--xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm104
-rw-r--r--xt/lib/Bugzilla/Test/Search/InjectionTest.pm77
-rw-r--r--xt/lib/Bugzilla/Test/Search/NotTest.pm61
-rw-r--r--xt/lib/Bugzilla/Test/Search/OperatorTest.pm103
-rw-r--r--xt/lib/Bugzilla/Test/Search/OrTest.pm141
9 files changed, 0 insertions, 2459 deletions
diff --git a/xt/lib/Bugzilla/Test/Search/AndTest.pm b/xt/lib/Bugzilla/Test/Search/AndTest.pm
deleted file mode 100644
index f34ba1f3a..000000000
--- a/xt/lib/Bugzilla/Test/Search/AndTest.pm
+++ /dev/null
@@ -1,52 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This test combines two field/operator combinations using AND in
-# a single boolean chart.
-package Bugzilla::Test::Search::AndTest;
-use parent qw(Bugzilla::Test::Search::OrTest);
-
-use Bugzilla::Test::Search::Constants;
-use List::MoreUtils qw(all);
-
-use constant type => 'AND';
-
-#############
-# Accessors #
-#############
-
-# In an AND test, bugs ARE supposed to be contained only if they are contained
-# by ALL tests.
-sub bug_is_contained {
- my ($self, $number) = @_;
- return all { $_->bug_is_contained($number) } $self->field_tests;
-}
-
-sub _bug_will_actually_be_contained {
- my ($self, $number) = @_;
- return all { $_->will_actually_contain_bug($number) } $self->field_tests;
-}
-
-##############################
-# Bugzilla::Search arguments #
-##############################
-
-sub search_params {
- my ($self) = @_;
- my @all_params = map { $_->search_params } $self->field_tests;
- my %params;
- my $chart = 0;
- foreach my $item (@all_params) {
- $params{"field0-$chart-0"} = $item->{'field0-0-0'};
- $params{"type0-$chart-0"} = $item->{'type0-0-0'};
- $params{"value0-$chart-0"} = $item->{'value0-0-0'};
- $chart++;
- }
- return \%params;
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/Constants.pm b/xt/lib/Bugzilla/Test/Search/Constants.pm
deleted file mode 100644
index 5d84ec6ff..000000000
--- a/xt/lib/Bugzilla/Test/Search/Constants.pm
+++ /dev/null
@@ -1,1203 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-
-# These are constants used by Bugzilla::Test::Search.
-# See the comment at the top of that package for a general overview
-# of how the search test works, and how the constants are used.
-# More detailed information on each constant is available in the comments
-# in this file.
-package Bugzilla::Test::Search::Constants;
-use parent qw(Exporter);
-use Bugzilla::Constants;
-use Bugzilla::Util qw(generate_random_password);
-
-our @EXPORT = qw(
- ATTACHMENT_FIELDS
- BROKEN_NOT
- COLUMN_TRANSLATION
- COMMENT_FIELDS
- CUSTOM_FIELDS
- CUSTOM_SEARCH_TESTS
- FIELD_SIZE
- FIELD_SUBSTR_SIZE
- FLAG_FIELDS
- INJECTION_BROKEN_FIELD
- INJECTION_BROKEN_OPERATOR
- INJECTION_TESTS
- KNOWN_BROKEN
- NUM_BUGS
- NUM_SEARCH_TESTS
- SKIP_FIELDS
- SPECIAL_PARAM_TESTS
- SUBSTR_NO_FIELD_ADD
- SUBSTR_SIZE
- TESTS
- TESTS_PER_RUN
- USER_FIELDS
-);
-
-# Bug 1 is designed to be found by all the "equals" tests. It has
-# multiple values for several fields where other fields only have
-# one value.
-#
-# Bug 2 and 3 have a dependency relationship with Bug 1,
-# but show up in "not equals" tests. We do use bug 2 in multiple-value
-# tests.
-#
-# Bug 4 should never show up in any equals test, and has no relationship
-# with any other bug. However, it does have all its fields set.
-#
-# Bug 5 only has values set for mandatory fields, to expose problems
-# that happen with "not equals" tests failing to catch bugs that don't
-# have a value set at all.
-#
-# Bug 6 is a clone of Bug 1, but is in a group that the searcher isn't
-# in.
-use constant NUM_BUGS => 6;
-
-# How many tests there are for each operator/field combination other
-# than the "contains" tests.
-use constant NUM_SEARCH_TESTS => 3;
-# This is how many tests get run for each field/operator.
-use constant TESTS_PER_RUN => NUM_SEARCH_TESTS + NUM_BUGS;
-
-# This is how many random characters we generate for most fields' names.
-# (Some fields can't be this long, though, so they have custom lengths
-# in Bugzilla::Test::Search).
-use constant FIELD_SIZE => 30;
-
-# These are the custom fields that are created if the BZ_MODIFY_DATABASE_TESTS
-# environment variable is set.
-use constant CUSTOM_FIELDS => {
- FIELD_TYPE_FREETEXT, 'cf_freetext',
- FIELD_TYPE_SINGLE_SELECT, 'cf_single_select',
- FIELD_TYPE_MULTI_SELECT, 'cf_multi_select',
- FIELD_TYPE_TEXTAREA, 'cf_textarea',
- FIELD_TYPE_DATETIME, 'cf_datetime',
- FIELD_TYPE_BUG_ID, 'cf_bugid',
-};
-
-# This translates fielddefs names into Search column names.
-use constant COLUMN_TRANSLATION => {
- creation_ts => 'opendate',
- delta_ts => 'changeddate',
- work_time => 'actual_time',
-};
-
-# Make comment field names to their Bugzilla::Comment accessor.
-use constant COMMENT_FIELDS => {
- longdesc => 'body',
- commenter => 'author',
- 'longdescs.isprivate' => 'is_private',
-};
-
-# Same as above, for Bugzilla::Attachment.
-use constant ATTACHMENT_FIELDS => {
- mimetype => 'contenttype',
- submitter => 'attacher',
- thedata => 'data',
-};
-
-# Same, for Bugzilla::Flag.
-use constant FLAG_FIELDS => {
- 'flagtypes.name' => 'name',
- 'setters.login_name' => 'setter',
- 'requestees.login_name' => 'requestee',
-};
-
-# These are fields that we don't test. Test::More will mark these
-# "TODO & SKIP", and not run tests for them at all.
-#
-# We don't support days_elapsed or owner_idle_time yet.
-use constant SKIP_FIELDS => qw(
- owner_idle_time
- days_elapsed
-);
-
-# All the fields that represent users.
-use constant USER_FIELDS => qw(
- assigned_to
- cc
- reporter
- qa_contact
- commenter
- attachments.submitter
- setters.login_name
- requestees.login_name
-);
-
-# For the "substr"-type searches, how short of a substring should
-# we use? The goal is to be shorter than the full string, but
-# long enough to still be globally unique.
-use constant SUBSTR_SIZE => 20;
-# However, for some fields, we use a different size.
-use constant FIELD_SUBSTR_SIZE => {
- alias => 11,
- # Just the month and day.
- deadline => -5,
- creation_ts => -8,
- delta_ts => -8,
- percentage_complete => 1,
- work_time => 3,
- remaining_time => 3,
- target_milestone => 15,
- longdesc => 25,
- # Just the hour and minute.
- FIELD_TYPE_DATETIME, -5,
-};
-
-# For most fields, we add the length of the name of the field plus
-# the SUBSTR_SIZE specified above to determine how large of a substring
-# we're going to use. However, for some fields, it doesn't make sense to
-# add in their field name this way.
-use constant SUBSTR_NO_FIELD_ADD => FIELD_TYPE_DATETIME, qw(
- target_milestone remaining_time percentage_complete work_time
- attachments.mimetype attachments.submitter attachments.filename
- attachments.description flagtypes.name
-);
-
-################
-# Known Broken #
-################
-
-# See the KNOWN_BROKEN constant for a general description of these
-# "_BROKEN" constants.
-
-# Shared between greaterthan and greaterthaneq.
-#
-# As with other fields, longdescs greaterthan matches if any comment
-# matches (which might be OK).
-#
-# Same for keywords, and cc. Logically, all of these might
-# be OK, but it makes the operation not the logical reverse of
-# lessthaneq. What we're really saying here by marking these broken
-# is that there ought to be some way of searching "all ccs" vs "any cc"
-# (and same for the other fields).
-use constant GREATERTHAN_BROKEN => (
- cc => { contains => [1] },
-);
-
-# allwords and allwordssubstr have these broken tests in common.
-use constant ALLWORDS_BROKEN => (
- # allwordssubstr on cc fields matches against a single cc,
- # instead of matching against all ccs on a bug.
- cc => { contains => [1] },
- # bug 828344 changed how these searches operate to revert back to the 4.0
- # behavour, so these tests need to be updated (bug 849117).
- 'flagtypes.name' => { contains => [1] },
- longdesc => { contains => [1] },
-);
-
-# Fields that don't generally work at all with changed* searches, but
-# probably should.
-use constant CHANGED_BROKEN => (
- classification => { contains => [1] },
- commenter => { contains => [1] },
- percentage_complete => { contains => [1] },
- 'requestees.login_name' => { contains => [1] },
- 'setters.login_name' => { contains => [1] },
- delta_ts => { contains => [1] },
-);
-
-# These are additional broken tests that changedfrom and changedto
-# have in common.
-use constant CHANGED_VALUE_BROKEN => (
- bug_group => { contains => [1] },
- cc => { contains => [1] },
- estimated_time => { contains => [1] },
- 'flagtypes.name' => { contains => [1] },
- keywords => { contains => [1] },
- 'longdescs.count' => { search => 1 },
- FIELD_TYPE_MULTI_SELECT, { contains => [1] },
-);
-
-
-# Any test listed in KNOWN_BROKEN gets marked TODO by Test::More
-# (using some complex code in Bugzilla::Test::Seach::FieldTest).
-# This means that if you run the test under "prove -v", these tests will
-# still show up as "not ok", but the test suite results won't show them
-# as a failure.
-#
-# This constant contains operators as keys, which point to hashes. The hashes
-# have field names as keys. Each field name points to a hash describing
-# how that field/operator combination is broken. The "contains"
-# array specifies that that particular "contains" test is expected
-# to fail. If "search" is set to 1, then we expect the creation of the
-# Bugzilla::Search object to fail.
-#
-# To allow handling custom fields, you can also use the field type as a key
-# instead of the field name. Specifying explicit field names always overrides
-# specifying a field type.
-#
-# Sometimes the operators have multiple tests, and one of them works
-# while the other fails. In this case, we have a special override for
-# "operator-value", which uniquely identifies tests.
-use constant KNOWN_BROKEN => {
- greaterthan => { GREATERTHAN_BROKEN },
- greaterthaneq => { GREATERTHAN_BROKEN },
-
- 'allwordssubstr-<1>' => { ALLWORDS_BROKEN },
- 'allwords-<1>' => {
- ALLWORDS_BROKEN,
- },
- 'anywords-<1>' => {
- 'flagtypes.name' => { contains => [1,2,3,4,5] },
- },
- 'anywords-<1> <2>' => {
- 'flagtypes.name' => { contains => [3,4,5] },
- },
- 'anywordssubstr-<1> <2>' => {
- 'flagtypes.name' => { contains => [3,4,5] },
- },
-
- # setters.login_name and requestees.login name aren't tracked individually
- # in bugs_activity, so can't be searched using this method.
- #
- # percentage_complete isn't tracked in bugs_activity (and it would be
- # really hard to track). However, it adds a 0=0 term instead of using
- # the changed* charts or simply denying them.
- #
- # delta_ts changedbefore/after should probably search for bugs based
- # on their delta_ts.
- #
- # creation_ts changedbefore/after should search for bug creation dates.
- #
- # The commenter field changedbefore/after should search for comment
- # creation dates.
- #
- # classification isn't being tracked properly in bugs_activity, I think.
- #
- # attach_data.thedata should search when attachments were created and
- # who they were created by.
- 'changedbefore' => {
- CHANGED_BROKEN,
- 'attach_data.thedata' => { contains => [1] },
- },
- 'changedafter' => {
- 'attach_data.thedata' => { contains => [2,3,4] },
- classification => { contains => [2,3,4] },
- commenter => { contains => [2,3,4] },
- delta_ts => { contains => [2,3,4] },
- percentage_complete => { contains => [2,3,4] },
- 'requestees.login_name' => { contains => [2,3,4] },
- 'setters.login_name' => { contains => [2,3,4] },
- },
- changedfrom => {
- CHANGED_BROKEN,
- CHANGED_VALUE_BROKEN,
- # All fields should have a way to search for "changing
- # from a blank value" probably.
- blocked => { contains => [3,4,5], no_criteria => 1 },
- dependson => { contains => [2,4,5], no_criteria => 1 },
- work_time => { contains => [1] },
- FIELD_TYPE_BUG_ID, { contains => [5], no_criteria => 1 },
- },
- # changeto doesn't find remaining_time changes (possibly due to us not
- # tracking that data properly).
- #
- # multi-valued fields are stored as comma-separated strings, so you
- # can't do changedfrom/to on them.
- #
- # Perhaps commenter can either tell you who the last commenter was,
- # or if somebody commented at a given time (combined with other
- # charts).
- #
- # longdesc changedto/from doesn't do anything; maybe it should.
- # Same for attach_data.thedata.
- changedto => {
- CHANGED_BROKEN,
- CHANGED_VALUE_BROKEN,
- 'attach_data.thedata' => { contains => [1] },
- longdesc => { contains => [1] },
- remaining_time => { contains => [1] },
- },
- changedby => {
- CHANGED_BROKEN,
- # This should probably search the attacher or anybody who changed
- # anything about an attachment at all.
- 'attach_data.thedata' => { contains => [1] },
- # This should probably search the reporter.
- creation_ts => { contains => [1] },
- },
- notequals => {
- 'flagtypes.name' => { contains => [1, 5] },
- longdesc => { contains => [1] },
- },
- notregexp => {
- 'flagtypes.name' => { contains => [1, 5] },
- longdesc => { contains => [1] },
- },
- notsubstring => {
- 'flagtypes.name' => { contains => [5] },
- longdesc => { contains => [1] },
- },
- nowords => {
- 'flagtypes.name' => { contains => [1, 5] },
- },
- nowordssubstr => {
- 'flagtypes.name' => { contains => [5] },
- },
-};
-
-###################
-# Broken NotTests #
-###################
-
-# Common BROKEN_NOT values for the changed* fields.
-use constant CHANGED_BROKEN_NOT => (
- "attach_data.thedata" => { contains => [1] },
- "classification" => { contains => [1] },
- "commenter" => { contains => [1] },
- "delta_ts" => { contains => [1] },
- percentage_complete => { contains => [1] },
- "requestees.login_name" => { contains => [1] },
- "setters.login_name" => { contains => [1] },
-);
-
-# For changedfrom and changedto.
-use constant CHANGED_FROM_TO_BROKEN_NOT => (
- 'longdescs.count' => { search => 1 },
- "bug_group" => { contains => [1] },
- "cc" => { contains => [1] },
- "estimated_time" => { contains => [1] },
- "flagtypes.name" => { contains => [1] },
- "keywords" => { contains => [1] },
- FIELD_TYPE_MULTI_SELECT, { contains => [1] },
-);
-
-# These are field/operator combinations that are broken when run under NOT().
-use constant BROKEN_NOT => {
- allwords => {
- cc => { contains => [1] },
- 'flagtypes.name' => { contains => [1, 5] },
- longdesc => { contains => [1] },
- },
- 'allwords-<1> <2>' => {
- cc => { },
- },
- allwordssubstr => {
- cc => { contains => [1] },
- 'flagtypes.name' => { contains => [5, 6] },
- longdesc => { contains => [1] },
- },
- 'allwordssubstr-<1>,<2>' => {
- cc => { },
- longdesc => { contains => [1] },
- },
- anyexact => {
- 'flagtypes.name' => { contains => [1, 2, 5] },
- },
- 'anywords-<1>' => {
- 'flagtypes.name' => { contains => [1, 2, 3, 4, 5] },
- },
- 'anywords-<1> <2>' => {
- 'flagtypes.name' => { contains => [3, 4, 5] },
- },
- anywordssubstr => {
- 'flagtypes.name' => { contains => [5] },
- },
- 'anywordssubstr-<1> <2>' => {
- 'flagtypes.name' => { contains => [3,4,5] },
- },
- casesubstring => {
- 'flagtypes.name' => { contains => [5] },
- },
- changedafter => {
- "attach_data.thedata" => { contains => [2, 3, 4] },
- "classification" => { contains => [2, 3, 4] },
- "commenter" => { contains => [2, 3, 4] },
- percentage_complete => { contains => [2, 3, 4] },
- "delta_ts" => { contains => [2, 3, 4] },
- "requestees.login_name" => { contains => [2, 3, 4] },
- "setters.login_name" => { contains => [2, 3, 4] },
- },
- changedbefore => {
- CHANGED_BROKEN_NOT,
- },
- changedby => {
- CHANGED_BROKEN_NOT,
- creation_ts => { contains => [1] },
- work_time => { contains => [1] },
- },
- changedfrom => {
- CHANGED_BROKEN_NOT,
- CHANGED_FROM_TO_BROKEN_NOT,
- 'attach_data.thedata' => { },
- blocked => { contains => [1, 2] },
- dependson => { contains => [1, 3] },
- work_time => { contains => [1] },
- FIELD_TYPE_BUG_ID, { contains => [1 .. 4] },
- },
- changedto => {
- CHANGED_BROKEN_NOT,
- CHANGED_FROM_TO_BROKEN_NOT,
- longdesc => { contains => [1] },
- "remaining_time" => { contains => [1] },
- },
- greaterthan => {
- cc => { contains => [1] },
- 'flagtypes.name' => { contains => [5] },
- },
- greaterthaneq => {
- cc => { contains => [1] },
- 'flagtypes.name' => { contains => [2, 5] },
- },
- equals => {
- 'flagtypes.name' => { contains => [1, 5] },
- },
- notequals => {
- longdesc => { contains => [1] },
- },
- notregexp => {
- longdesc => { contains => [1] },
- },
- notsubstring => {
- longdesc => { contains => [1] },
- },
- 'nowords-<1>' => {
- 'flagtypes.name' => { contains => [5] },
- },
- 'nowordssubstr-<1>' => {
- 'flagtypes.name' => { contains => [5] },
- },
- lessthan => {
- 'flagtypes.name' => { contains => [5] },
- },
- lessthaneq => {
- 'flagtypes.name' => { contains => [1, 5] },
- },
- regexp => {
- 'flagtypes.name' => { contains => [1, 5] },
- longdesc => { contains => [1] },
- },
- substring => {
- 'flagtypes.name' => { contains => [5] },
- longdesc => { contains => [1] },
- },
-};
-
-#############
-# Overrides #
-#############
-
-# These overrides are used in the TESTS constant, below.
-
-# Regex tests need unique test values for certain fields.
-use constant REGEX_OVERRIDE => {
- 'attachments.mimetype' => { value => '^text/x-1-' },
- bug_file_loc => { value => '^http://1-' },
- see_also => { value => '^http://1-' },
- blocked => { value => '^<1>$' },
- dependson => { value => '^<1>$' },
- bug_id => { value => '^<1>$' },
- 'attachments.isobsolete' => { value => '^1'},
- 'attachments.ispatch' => { value => '^1'},
- 'attachments.isprivate' => { value => '^1' },
- cclist_accessible => { value => '^1' },
- reporter_accessible => { value => '^1' },
- everconfirmed => { value => '^1' },
- 'longdescs.count' => { value => '^3' },
- 'longdescs.isprivate' => { value => '^1' },
- creation_ts => { value => '^2037-01-01' },
- delta_ts => { value => '^2037-01-01' },
- deadline => { value => '^2037-02-01' },
- estimated_time => { value => '^1.0' },
- remaining_time => { value => '^9.0' },
- work_time => { value => '^1.0' },
- longdesc => { value => '^1-' },
- percentage_complete => { value => '^10' },
- FIELD_TYPE_BUG_ID, { value => '^<1>$' },
- FIELD_TYPE_DATETIME, { value => '^2037-03-01' }
-};
-
-# Common overrides between lessthan and lessthaneq.
-use constant LESSTHAN_OVERRIDE => (
- alias => { contains => [1,5] },
- estimated_time => { contains => [1,5] },
- qa_contact => { contains => [1,5] },
- resolution => { contains => [1,5] },
- status_whiteboard => { contains => [1,5] },
- FIELD_TYPE_TEXTAREA, { contains => [1,5] },
- FIELD_TYPE_FREETEXT, { contains => [1,5] },
-);
-
-# The mandatorily-set fields have values higher than <1>,
-# so bug 5 shows up.
-use constant GREATERTHAN_OVERRIDE => (
- classification => { contains => [2,3,4,5] },
- assigned_to => { contains => [2,3,4,5] },
- bug_id => { contains => [2,3,4,5] },
- bug_group => { contains => [1,2,3,4] },
- bug_severity => { contains => [2,3,4,5] },
- bug_status => { contains => [2,3,4,5] },
- component => { contains => [2,3,4,5] },
- commenter => { contains => [2,3,4,5] },
- # keywords matches if *any* keyword matches
- keywords => { contains => [1,2,3,4] },
- longdesc => { contains => [1,2,3,4] },
- op_sys => { contains => [2,3,4,5] },
- priority => { contains => [2,3,4,5] },
- product => { contains => [2,3,4,5] },
- reporter => { contains => [2,3,4,5] },
- rep_platform => { contains => [2,3,4,5] },
- short_desc => { contains => [2,3,4,5] },
- version => { contains => [2,3,4,5] },
- tag => { contains => [1,2,3,4] },
- target_milestone => { contains => [2,3,4,5] },
- # Bug 2 is the only bug besides 1 that has a Requestee set.
- 'requestees.login_name' => { contains => [2] },
- FIELD_TYPE_SINGLE_SELECT, { contains => [2,3,4,5] },
- # Override SINGLE_SELECT for resolution.
- resolution => { contains => [2,3,4] },
- # MULTI_SELECTs match if *any* value matches
- FIELD_TYPE_MULTI_SELECT, { contains => [1,2,3,4] },
-);
-
-# For all positive multi-value types.
-use constant MULTI_BOOLEAN_OVERRIDE => (
- 'attachments.ispatch' => { value => '1,1', contains => [1] },
- 'attachments.isobsolete' => { value => '1,1', contains => [1] },
- 'attachments.isprivate' => { value => '1,1', contains => [1] },
- cclist_accessible => { value => '1,1', contains => [1] },
- reporter_accessible => { value => '1,1', contains => [1] },
- 'longdescs.isprivate' => { value => '1,1', contains => [1] },
- everconfirmed => { value => '1,1', contains => [1] },
-);
-
-# Same as above, for negative multi-value types.
-use constant NEGATIVE_MULTI_BOOLEAN_OVERRIDE => (
- 'attachments.ispatch' => { value => '1,1', contains => [2,3,4,5] },
- 'attachments.isobsolete' => { value => '1,1', contains => [2,3,4,5] },
- 'attachments.isprivate' => { value => '1,1', contains => [2,3,4,5] },
- cclist_accessible => { value => '1,1', contains => [2,3,4,5] },
- reporter_accessible => { value => '1,1', contains => [2,3,4,5] },
- 'longdescs.isprivate' => { value => '1,1', contains => [2,3,4,5] },
- everconfirmed => { value => '1,1', contains => [2,3,4,5] },
-);
-
-# For anyexact and anywordssubstr
-use constant ANY_OVERRIDE => (
- 'longdescs.count' => { contains => [1,2,3,4] },
- 'work_time' => { value => '1.0,2.0' },
- dependson => { value => '<1>,<3>', contains => [1,3] },
- MULTI_BOOLEAN_OVERRIDE,
-);
-
-# For all the changed* searches. The ones that have empty contains
-# are fields that never change in value, or will never be rationally
-# tracked in bugs_activity.
-use constant CHANGED_OVERRIDE => (
- 'attachments.submitter' => { contains => [] },
- bug_id => { contains => [] },
- reporter => { contains => [] },
- tag => { contains => [] },
-);
-
-#########
-# Tests #
-#########
-
-# The basic format of this is a hashref, where the keys are operators,
-# and each operator has an arrayref of tests that it runs. The tests
-# are hashrefs, with the following possible keys:
-#
-# contains: This is a list of bug numbers that the search is expected
-# to contain. (This is bug numbers, like 1,2,3, not the bug
-# ids. For a description of each bug number, see NUM_BUGS.)
-# Any bug not listed in "contains" must *not* show up in the
-# search result.
-# value: The value that you're searching for. There are certain special
-# codes that will be replaced with bug values when the tests are
-# run. In these examples below, "#" indicates a bug number:
-#
-# <#> - The field value for this bug.
-#
-# For any operator that has the string "word" in it, this is
-# *all* the values for the current field from the numbered bug,
-# joined by a space.
-#
-# If the operator has the string "substr" in it, then we
-# take a substring of the value (for single-value searches)
-# or we take a substring of each value and join them (for
-# multi-value "word" searches). The length of the substring
-# is determined by the SUBSTR_SIZE constants above.)
-#
-# For other operators, this just becomes the first value from
-# the field for the numbered bug.
-#
-# So, if we were running the "equals" test and checking the
-# cc field, <1> would become the login name of the first cc on
-# Bug 1. If we did an "anywords" search test, it would become
-# a space-separated string of the login names of all the ccs
-# on Bug 1. If we did an "anywordssubstr" search test, it would
-# become a space-separated string of the first few characters
-# of each CC's login name on Bug 1.
-#
-# <#-id> - The bug id of the numbered bug.
-# <#-reporter> - The login name of the numbered bug's reporter.
-# <#-delta> - The delta_ts of the numbered bug.
-#
-# escape: If true, we will call quotemeta() on the value immediately
-# before passing it to Search.pm.
-#
-# transform: A function to call on any field value before inserting
-# it for a <#> replacement. The transformation function
-# gets all of the bug's values for the field as its arguments.
-# if_equal: This allows you to override "contains" for the case where
-# the transformed value (from calling the "transform" function)
-# is equal to the original value.
-#
-# override: This allows you to override "contains" and "values" for
-# certain fields.
-use constant TESTS => {
- equals => [
- { contains => [1], value => '<1>' },
- ],
- notequals => [
- { contains => [2,3,4,5], value => '<1>' },
- ],
- substring => [
- { contains => [1], value => '<1>',
- override => {
- percentage_complete => { contains => [1,2,3] },
- }
- },
- ],
- casesubstring => [
- { contains => [1], value => '<1>',
- override => {
- percentage_complete => { contains => [1,2,3] },
- }
- },
- { contains => [], value => '<1>', transform => sub { lc($_[0]) },
- extra_name => 'lc', if_equal => { contains => [1] },
- override => {
- percentage_complete => { contains => [1,2,3] },
- }
- },
- ],
- notsubstring => [
- { contains => [2,3,4,5], value => '<1>',
- override => {
- percentage_complete => { contains => [4,5] },
- },
- }
- ],
- regexp => [
- { contains => [1], value => '<1>', escape => 1,
- override => {
- percentage_complete => { value => '^10' },
- }
- },
- { contains => [1], value => '^1-', override => REGEX_OVERRIDE },
- ],
- notregexp => [
- { contains => [2,3,4,5], value => '<1>', escape => 1,
- override => {
- percentage_complete => { value => '^10' },
- }
- },
- { contains => [2,3,4,5], value => '^1-', override => REGEX_OVERRIDE },
- ],
- lessthan => [
- { contains => [1], value => 2,
- override => {
- # A lot of these contain bug 5 because an empty value is validly
- # less than the specified value.
- bug_file_loc => { value => 'http://2-', contains => [1,5] },
- see_also => { value => 'http://2-' },
- 'attachments.mimetype' => { value => 'text/x-2-' },
- blocked => { value => '<4-id>', contains => [1,2] },
- dependson => { value => '<3-id>', contains => [1,3] },
- bug_id => { value => '<2-id>' },
- 'attachments.isprivate' => { value => 1, contains => [2,3,4] },
- 'attachments.isobsolete' => { value => 1, contains => [2,3,4] },
- 'attachments.ispatch' => { value => 1, contains => [2,3,4] },
- cclist_accessible => { value => 1, contains => [2,3,4,5] },
- reporter_accessible => { value => 1, contains => [2,3,4,5] },
- 'longdescs.count' => { value => 3, contains => [2,3,4,5] },
- 'longdescs.isprivate' => { value => 1, contains => [1,2,3,4,5] },
- everconfirmed => { value => 1, contains => [2,3,4,5] },
- creation_ts => { value => '2037-01-02', contains => [1,5] },
- delta_ts => { value => '2037-01-02', contains => [1,5] },
- deadline => { value => '2037-02-02', contains => [1,5] },
- remaining_time => { value => 10, contains => [1,5] },
- percentage_complete => { value => 11, contains => [1,5] },
- longdesc => { value => '2-', contains => [1,5] },
- work_time => { value => 1, contains => [5] },
- FIELD_TYPE_BUG_ID, { value => '<2>', contains => [1,5] },
- FIELD_TYPE_DATETIME, { value => '2037-03-02', contains => [1,5] },
- LESSTHAN_OVERRIDE,
- }
- },
- ],
- lessthaneq => [
- { contains => [1], value => '<1>',
- override => {
- 'attachments.isobsolete' => { value => 0, contains => [2,3,4] },
- 'attachments.ispatch' => { value => 0, contains => [2,3,4] },
- 'attachments.isprivate' => { value => 0, contains => [2,3,4] },
- cclist_accessible => { value => 0, contains => [2,3,4,5] },
- reporter_accessible => { value => 0, contains => [2,3,4,5] },
- 'longdescs.count' => { value => 2, contains => [2,3,4,5] },
- 'longdescs.isprivate' => { value => -1, contains => [] },
- everconfirmed => { value => 0, contains => [2,3,4,5] },
- bug_file_loc => { contains => [1,5] },
- blocked => { contains => [1,2] },
- deadline => { contains => [1,5] },
- dependson => { contains => [1,3] },
- creation_ts => { contains => [1,5] },
- delta_ts => { contains => [1,5] },
- remaining_time => { contains => [1,5] },
- longdesc => { contains => [1,5] },
- percentage_complete => { contains => [1,5] },
- work_time => { value => 1, contains => [1,5] },
- FIELD_TYPE_BUG_ID, { contains => [1,5] },
- FIELD_TYPE_DATETIME, { contains => [1,5] },
- LESSTHAN_OVERRIDE,
- },
- },
- ],
- greaterthan => [
- { contains => [2,3,4], value => '<1>',
- override => {
- dependson => { contains => [3] },
- blocked => { contains => [2] },
- 'attachments.ispatch' => { value => 0, contains => [1] },
- 'attachments.isobsolete' => { value => 0, contains => [1] },
- 'attachments.isprivate' => { value => 0, contains => [1] },
- cclist_accessible => { value => 0, contains => [1] },
- reporter_accessible => { value => 0, contains => [1] },
- 'longdescs.count' => { value => 2, contains => [1] },
- 'longdescs.isprivate' => { value => 0, contains => [1] },
- everconfirmed => { value => 0, contains => [1] },
- 'flagtypes.name' => { value => 2, contains => [2,3,4] },
- GREATERTHAN_OVERRIDE,
- },
- },
- ],
- greaterthaneq => [
- { contains => [2,3,4], value => '<2>',
- override => {
- 'attachments.ispatch' => { value => 1, contains => [1] },
- 'attachments.isobsolete' => { value => 1, contains => [1] },
- 'attachments.isprivate' => { value => 1, contains => [1] },
- cclist_accessible => { value => 1, contains => [1] },
- reporter_accessible => { value => 1, contains => [1] },
- 'longdescs.count' => { value => 3, contains => [1] },
- 'longdescs.isprivate' => { value => 1, contains => [1] },
- everconfirmed => { value => 1, contains => [1] },
- dependson => { value => '<3>', contains => [1,3] },
- blocked => { contains => [1,2] },
- GREATERTHAN_OVERRIDE,
- }
- },
- ],
- matches => [
- { contains => [1], value => '<1>' },
- ],
- notmatches => [
- { contains => [2,3,4,5], value => '<1>' },
- ],
- anyexact => [
- { contains => [1,2], value => '<1>, <2>',
- override => { ANY_OVERRIDE } },
- ],
- anywordssubstr => [
- { contains => [1,2], value => '<1> <2>',
- override => {
- ANY_OVERRIDE,
- percentage_complete => { contains => [1,2,3] },
- }
- },
- ],
- allwordssubstr => [
- { contains => [1], value => '<1>',
- override => {
- MULTI_BOOLEAN_OVERRIDE,
- # We search just the number "1" for percentage_complete,
- # which matches a lot of bugs.
- percentage_complete => { contains => [1,2,3] },
- },
- },
- { contains => [], value => '<1>,<2>',
- override => {
- dependson => { value => '<1-id> <3-id>', contains => [] },
- # bug 3 has the value "21" here, so matches "2,1"
- percentage_complete => { value => '<2>,<3>', contains => [3] },
- # 1 0 matches bug 1, which has both public and private comments.
- 'longdescs.isprivate' => { contains => [1] },
- }
- },
- ],
- nowordssubstr => [
- { contains => [2,3,4,5], value => '<1>',
- override => {
- # longdescs.isprivate translates to "1 0", so no bugs should
- # show up.
- 'longdescs.isprivate' => { contains => [] },
- percentage_complete => { contains => [4,5] },
- work_time => { contains => [2,3,4,5] },
- }
- },
- ],
- anywords => [
- { contains => [1], value => '<1>',
- override => {
- MULTI_BOOLEAN_OVERRIDE,
- }
- },
- { contains => [1,2], value => '<1> <2>',
- override => {
- MULTI_BOOLEAN_OVERRIDE,
- dependson => { value => '<1> <3>', contains => [1,3] },
- 'longdescs.count' => { contains => [1,2,3,4] },
- },
- },
- ],
- allwords => [
- { contains => [1], value => '<1>',
- override => { MULTI_BOOLEAN_OVERRIDE } },
- { contains => [], value => '<1> <2>',
- override => {
- dependson => { contains => [], value => '<2-id> <3-id>' },
- # 1 0 matches bug 1, which has both public and private comments.
- 'longdescs.isprivate' => { contains => [1] },
- }
- },
- ],
- nowords => [
- { contains => [2,3,4,5], value => '<1>',
- override => {
- # longdescs.isprivate translates to "1 0", so no bugs should
- # show up.
- 'longdescs.isprivate' => { contains => [] },
- work_time => { contains => [2,3,4,5] },
- }
- },
- ],
-
- changedbefore => [
- { contains => [1], value => '<1-delta>',
- override => {
- CHANGED_OVERRIDE,
- creation_ts => { contains => [1,5] },
- blocked => { contains => [1,2] },
- dependson => { contains => [1,3] },
- longdesc => { contains => [1,5] },
- 'longdescs.count' => { contains => [1,5] },
- }
- },
- ],
- changedafter => [
- { contains => [2,3,4], value => '<2-delta>',
- override => {
- CHANGED_OVERRIDE,
- creation_ts => { contains => [3,4] },
- # We only change this for one bug, and it doesn't match.
- 'longdescs.isprivate' => { contains => [] },
- # Same for everconfirmed.
- 'everconfirmed' => { contains => [] },
- # For blocked and dependson, they have the delta_ts of bug1
- # in the bugs_activity table, so they won't ever match.
- blocked => { contains => [] },
- dependson => { contains => [] },
- }
- },
- ],
- changedfrom => [
- { contains => [1], value => '<1>',
- override => {
- CHANGED_OVERRIDE,
- # The test never changes an already-set dependency field, but
- # we *can* attempt to test searching against an empty value,
- # which should get us some bugs.
- blocked => { value => '', contains => [1,2] },
- dependson => { value => '', contains => [1,3] },
- FIELD_TYPE_BUG_ID, { value => '', contains => [1,2,3,4] },
- # longdesc changedfrom doesn't make any sense.
- longdesc => { contains => [] },
- # Nor does creation_ts changedfrom.
- creation_ts => { contains => [] },
- 'attach_data.thedata' => { contains => [] },
- bug_id => { value => '<1-id>', contains => [] },
- },
- },
- ],
- changedto => [
- { contains => [1], value => '<1>',
- override => {
- CHANGED_OVERRIDE,
- # I can't imagine any use for creation_ts changedto.
- creation_ts => { contains => [] },
- }
- },
- ],
- changedby => [
- { contains => [1], value => '<1-reporter>',
- override => {
- CHANGED_OVERRIDE,
- blocked => { contains => [1,2] },
- dependson => { contains => [1,3] },
- },
- },
- ],
- # XXX these need tests developed
- isempty => [],
- isnotempty => [],
-};
-
-# Fields that do not behave as we expect, for InjectionTest.
-# search => 1 means the Bugzilla::Search creation fails.
-# sql_error is a regex that specifies a SQL error that's OK for us to throw.
-# operator_ok overrides the "brokenness" of certain operators, so that they
-# are always OK for that field/operator combination.
-use constant INJECTION_BROKEN_FIELD => {
- # Pg can't run injection tests against integer or date fields. See bug 577557.
- 'attachments.isobsolete' => { db_skip => ['Pg'] },
- 'attachments.ispatch' => { db_skip => ['Pg'] },
- 'attachments.isprivate' => { db_skip => ['Pg'] },
- blocked => { db_skip => ['Pg'] },
- bug_id => { db_skip => ['Pg'] },
- cclist_accessible => { db_skip => ['Pg'] },
- creation_ts => { db_skip => ['Pg'] },
- days_elapsed => { db_skip => ['Pg'] },
- dependson => { db_skip => ['Pg'] },
- deadline => { db_skip => ['Pg'] },
- delta_ts => { db_skip => ['Pg'] },
- estimated_time => { db_skip => ['Pg'] },
- everconfirmed => { db_skip => ['Pg'] },
- 'longdescs.isprivate' => { db_skip => ['Pg'] },
- percentage_complete => { db_skip => ['Pg'] },
- remaining_time => { db_skip => ['Pg'] },
- reporter_accessible => { db_skip => ['Pg'] },
- work_time => { db_skip => ['Pg'] },
- FIELD_TYPE_BUG_ID, { db_skip => ['Pg'] },
- FIELD_TYPE_DATETIME, { db_skip => ['Pg'] },
- owner_idle_time => { search => 1 },
- 'longdescs.count' => {
- search => 1,
- db_skip => ['Pg'],
- operator_ok => [qw(allwords allwordssubstr anywordssubstr casesubstring
- changedbefore changedafter greaterthan greaterthaneq
- lessthan lessthaneq notregexp notsubstring
- nowordssubstr regexp substring anywords
- notequals nowords equals anyexact)],
- },
-};
-
-# Operators that do not behave as we expect, for InjectionTest.
-# search => 1 means the Bugzilla::Search creation fails, but
-# field_ok contains fields that it does actually succeed for.
-use constant INJECTION_BROKEN_OPERATOR => {
- changedafter => { search => 1, field_ok => ['creation_ts'] },
- changedbefore => { search => 1, field_ok => ['creation_ts'] },
- changedby => { search => 1 },
- isempty => { search => 1 },
- isnotempty => { search => 1 },
-};
-
-# Tests run by Bugzilla::Test::Search::InjectionTest.
-# We have to make sure the values are all one word or they'll be split
-# up by the multi-word tests.
-use constant INJECTION_TESTS => (
- { value => ';SEMICOLON_TEST' },
- { value => '--COMMENT_TEST' },
- { value => "'QUOTE_TEST" },
- { value => "';QUOTE_SEMICOLON_TEST" },
- { value => '/*STAR_COMMENT_TEST' }
-);
-
-#################
-# Special Tests #
-#################
-
-use constant SPECIAL_PARAM_TESTS => (
- { field => 'bug_status', operator => 'anyexact', value => '__open__',
- contains => [5] },
- { field => 'bug_status', operator => 'anyexact', value => '__closed__',
- contains => [1,2,3,4] },
- { field => 'bug_status', operator => 'anyexact', value => '__all__',
- contains => [1,2,3,4,5] },
-
- { field => 'resolution', operator => 'anyexact', value => '---',
- contains => [5] },
-
- # email* query parameters.
- { field => 'assigned_to', operator => 'anyexact',
- value => '<1>, <2-reporter>', contains => [1,2],
- extra_params => { emailreporter1 => 1 } },
- { field => 'assigned_to', operator => 'equals',
- value => '<1>', extra_name => 'email2', contains => [],
- extra_params => {
- email2 => generate_random_password(100), emaillongdesc2 => 1,
- },
- },
-
- # standard pronouns
- { field => 'assigned_to', operator => 'equals', value => '%assignee%',
- contains => [1,2,3,4,5] },
- { field => 'reporter', operator => 'equals', value => '%reporter%',
- contains => [1,2,3,4,5] },
- { field => 'qa_contact', operator => 'equals', value => '%qacontact%',
- contains => [1,2,3,4,5] },
- { field => 'cc', operator => 'equals', value => '%user%',
- contains => [1] },
- # group pronouns
- { field => 'reporter', operator => 'equals',
- value => '%group.<1-bug_group>%', contains => [1,2,3,4,5] },
- { field => 'assigned_to', operator => 'equals',
- value => '%group.<1-bug_group>%', contains => [1,2,3,4,5] },
- { field => 'qa_contact', operator => 'equals',
- value => '%group.<1-bug_group>%', contains => [1,2,3,4] },
- { field => 'cc', operator => 'equals',
- value => '%group.<1-bug_group>%', contains => [1,2,3,4] },
- { field => 'commenter', operator => 'equals',
- value => '%group.<1-bug_group>%', contains => [1,2,3,4,5] },
-);
-
-use constant CUSTOM_SEARCH_TESTS => (
- { name => 'OP without CP', contains => [1],
- params => [
- { f => 'OP' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- ]
- },
-
- { name => 'Empty OP/CP pair before criteria', contains => [1],
- params => [
- { f => 'OP' }, { f => 'CP' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- ]
- },
-
- { name => 'Empty OP/CP pair after criteria', contains => [1],
- params => [
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'OP' }, { f => 'CP' },
- ]
- },
-
- { name => 'empty OP/CP mid criteria', contains => [1],
- columns => ['assigned_to'],
- params => [
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'OP' }, { f => 'CP' },
- { f => 'assigned_to', o => 'substr', v => '@' },
- ]
- },
-
- { name => 'bug_id = 1 AND assigned_to contains @', contains => [1],
- columns => ['assigned_to'],
- params => [
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'substr', v => '@' },
- ]
- },
-
- { name => 'NOT(bug_id = 1) AND NOT(assigned_to = 2)',
- contains => [3,4,5],
- columns => ['assigned_to'],
- params => [
- { n => 1, f => 'bug_id', o => 'equals', v => '<1>' },
- { n => 1, f => 'assigned_to', o => 'equals', v => '<2>' },
- ]
- },
-
- { name => 'bug_id = 1 OR assigned_to = 2', contains => [1,2],
- columns => ['assigned_to'], top_params => { j_top => 'OR' },
- params => [
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'equals', v => '<2>' },
- ]
- },
-
- { name => 'NOT(bug_id = 1 AND assigned_to = 1)', contains => [2,3,4,5],
- columns => ['assigned_to'],
- params => [
- { f => 'OP', n => 1 },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'equals', v => '<1>' },
- { f => 'CP' },
- ]
- },
-
-
- { name => '(bug_id = 1 AND assigned_to contains @) '
- . ' OR (bug_id = 2 AND assigned_to contains @)',
- contains => [1,2], columns => ['assigned_to'],
- top_params => { j_top => 'OR' },
- params => [
- { f => 'OP' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'substr', v => '@' },
- { f => 'CP' },
- { f => 'OP' },
- { f => 'bug_id', o => 'equals', v => '<2>' },
- { f => 'assigned_to', o => 'substr', v => '@' },
- { f => 'CP' },
- ]
- },
-
- { name => '(bug_id = 1 OR assigned_to = 2) '
- . ' AND (bug_id = 2 OR assigned_to = 1)',
- contains => [1,2], columns => ['assigned_to'],
- params => [
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'equals', v => '<2>' },
- { f => 'CP' },
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<2>' },
- { f => 'assigned_to', o => 'equals', v => '<1>' },
- { f => 'CP' },
- ]
- },
-
- { name => 'bug_id = 3 OR ( (bug_id = 1 OR assigned_to = 2) '
- . ' AND (bug_id = 2 OR assigned_to = 1) )',
- contains => [1,2,3], columns => ['assigned_to'],
- top_params => { j_top => 'OR' },
- params => [
- { f => 'bug_id', o => 'equals', v => '<3>' },
- { f => 'OP' },
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'equals', v => '<2>' },
- { f => 'CP' },
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<2>' },
- { f => 'assigned_to', o => 'equals', v => '<1>' },
- { f => 'CP' },
- { f => 'CP' },
- ]
- },
-
- { name => 'bug_id = 3 OR ( (bug_id = 1 OR assigned_to = 2) '
- . ' AND (bug_id = 2 OR assigned_to = 1) ) OR bug_id = 4',
- contains => [1,2,3,4], columns => ['assigned_to'],
- top_params => { j_top => 'OR' },
- params => [
- { f => 'bug_id', o => 'equals', v => '<3>' },
- { f => 'OP' },
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<1>' },
- { f => 'assigned_to', o => 'equals', v => '<2>' },
- { f => 'CP' },
- { f => 'OP', j => 'OR' },
- { f => 'bug_id', o => 'equals', v => '<2>' },
- { f => 'assigned_to', o => 'equals', v => '<1>' },
- { f => 'CP' },
- { f => 'CP' },
- { f => 'bug_id', o => 'equals', v => '<4>' },
- ]
- },
-
-);
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/CustomTest.pm b/xt/lib/Bugzilla/Test/Search/CustomTest.pm
deleted file mode 100644
index 132e5ac40..000000000
--- a/xt/lib/Bugzilla/Test/Search/CustomTest.pm
+++ /dev/null
@@ -1,101 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This module represents a test with custom URL parameters.
-# Tests like this are specified in CUSTOM_SEARCH_TESTS in
-# Bugzilla::Test::Search::Constants.
-package Bugzilla::Test::Search::CustomTest;
-use parent qw(Bugzilla::Test::Search::FieldTest);
-use strict;
-use warnings;
-
-use Bugzilla::Test::Search::FieldTest;
-use Bugzilla::Test::Search::OperatorTest;
-
-use Storable qw(dclone);
-
-###############
-# Constructor #
-###############
-
-sub new {
- my ($class, $test, $search_test) = @_;
- bless { raw_test => dclone($test), search_test => $search_test }, $class;
-}
-
-#############
-# Accessors #
-#############
-
-sub search_test { return $_[0]->{search_test} }
-sub name { return 'Custom: ' . $_[0]->test->{name} }
-sub test { return $_[0]->{raw_test} }
-
-sub operator_test { die "unimplemented" }
-sub field_object { die "unimplemented" }
-sub main_value { die "unimplenmented" }
-sub test_value { die "unimplemented" }
-# Custom tests don't use transforms.
-sub transformed_value_was_equal { 0 }
-sub debug_value {
- my ($self) = @_;
- my $string = '';
- my $params = $self->search_params;
- foreach my $param (keys %$params) {
- $string .= $param . "=" . $params->{$param} . '&';
- }
- chop($string);
- return $string;
-}
-
-# The tests we know are broken for this operator/field combination.
-sub _known_broken { return {} }
-sub contains_known_broken { return undef }
-sub search_known_broken { return undef }
-sub field_not_yet_implemented { return undef }
-sub invalid_field_operator_combination { return undef }
-
-#########################################
-# Accessors: Bugzilla::Search Arguments #
-#########################################
-
-# Converts the f, o, v rows into f0, o0, v0, etc. and translates
-# the values appropriately.
-sub search_params {
- my ($self) = @_;
-
- my %params = %{ $self->test->{top_params} || {} };
- my $counter = 0;
- foreach my $row (@{ $self->test->{params} }) {
- $row->{v} = $self->translate_value($row) if exists $row->{v};
- foreach my $key (keys %$row) {
- $params{"${key}$counter"} = $row->{$key};
- }
- $counter++;
- }
-
- return \%params;
-}
-
-sub translate_value {
- my ($self, $row) = @_;
- my $as_test = { field => $row->{f}, operator => $row->{o},
- value => $row->{v} };
- my $operator_test = new Bugzilla::Test::Search::OperatorTest($row->{o},
- $self->search_test);
- my $field = Bugzilla::Field->check($row->{f});
- my $field_test = new Bugzilla::Test::Search::FieldTest($operator_test,
- $field, $as_test);
- return $field_test->translated_value;
-}
-
-sub search_columns {
- my ($self) = @_;
- return ['bug_id', @{ $self->test->{columns} || [] }];
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/FieldTest.pm b/xt/lib/Bugzilla/Test/Search/FieldTest.pm
deleted file mode 100644
index 5e86d92e2..000000000
--- a/xt/lib/Bugzilla/Test/Search/FieldTest.pm
+++ /dev/null
@@ -1,617 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This module represents the tests that get run on a single
-# operator/field combination for Bugzilla::Test::Search.
-# This is where all the actual testing happens.
-package Bugzilla::Test::Search::FieldTest;
-
-use strict;
-use warnings;
-use Bugzilla::Search;
-use Bugzilla::Test::Search::Constants;
-use Bugzilla::Util qw(trim);
-
-use Data::Dumper;
-use Scalar::Util qw(blessed);
-use Test::More;
-use Test::Exception;
-
-###############
-# Constructor #
-###############
-
-sub new {
- my ($class, $operator_test, $field, $test) = @_;
- return bless { operator_test => $operator_test,
- field_object => $field,
- raw_test => $test }, $class;
-}
-
-#############
-# Accessors #
-#############
-
-sub num_tests { return TESTS_PER_RUN }
-
-# The Bugzilla::Test::Search::OperatorTest that this is a child of.
-sub operator_test { return $_[0]->{operator_test} }
-# The Bugzilla::Field being tested.
-sub field_object { return $_[0]->{field_object} }
-# The name of the field being tested, which we need much more often
-# than we need the object.
-sub field {
- my ($self) = @_;
- $self->{field_name} ||= $self->field_object->name;
- return $self->{field_name};
-}
-# The Bugzilla::Test::Search object that this is a child of.
-sub search_test { return $_[0]->operator_test->search_test }
-# The operator being tested
-sub operator { return $_[0]->operator_test->operator }
-# The bugs currently being tested by Bugzilla::Test::Search.
-sub bugs { return $_[0]->search_test->bugs }
-sub bug {
- my $self = shift;
- return $self->search_test->bug(@_);
-}
-sub number {
- my ($self, $id) = @_;
- foreach my $number (1..NUM_BUGS) {
- return $number if $self->search_test->bug($number)->id == $id;
- }
- return 0;
-}
-
-# The name displayed for this test by Test::More. Used in test descriptions.
-sub name {
- my ($self) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
- my $value = $self->main_value;
-
- my $name = "$field-$operator-$value";
- if (my $extra_name = $self->test->{extra_name}) {
- $name .= "-$extra_name";
- }
- return $name;
-}
-
-# The appropriate value from the TESTS constant for this test, taking
-# into account overrides.
-sub test {
- my $self = shift;
- return $self->{test} if $self->{test};
-
- my %test = %{ $self->{raw_test} };
-
- # We have field name overrides...
- my $override = $test{override}->{$self->field};
- # And also field type overrides.
- if (!$override) {
- $override = $test{override}->{$self->field_object->type} || {};
- }
-
- foreach my $key (%$override) {
- $test{$key} = $override->{$key};
- }
-
- $self->{test} = \%test;
- return $self->{test};
-}
-
-# All the values for all the bugs for this field.
-sub _field_values {
- my ($self) = @_;
- return $self->{field_values} if $self->{field_values};
-
- my %field_values;
- foreach my $number (1..NUM_BUGS) {
- $field_values{$number} = $self->_field_values_for_bug($number);
- }
- $self->{field_values} = \%field_values;
- return $self->{field_values};
-}
-# The values for this field for the numbered bug.
-sub bug_values {
- my ($self, $number) = @_;
- return @{ $self->_field_values->{$number} };
-}
-
-# The untranslated, non-overriden value--used in the name of the test
-# and other places.
-sub main_value { return $_[0]->{raw_test}->{value} }
-# The untranslated test value, taking into account overrides.
-sub test_value { return $_[0]->test->{value} };
-# The value translated appropriately for passing to Bugzilla::Search.
-sub translated_value {
- my $self = shift;
- if (!exists $self->{translated_value}) {
- my $value = $self->search_test->value_translation_cache($self);
- if (!defined $value) {
- $value = $self->_translate_value();
- $self->search_test->value_translation_cache($self, $value);
- }
- $self->{translated_value} = $value;
- }
- return $self->{translated_value};
-}
-# Used in failure diagnostic messages.
-sub debug_fail {
- my ($self, $number, $results, $sql) = @_;
- my @expected = @{ $self->test->{contains} };
- my @results = sort
- map { $self->number($_) }
- map { $_->[0] }
- @$results;
- return
- " Value: '" . $self->translated_value . "'\n" .
- "Expected: [" . join(',', @expected) . "]\n" .
- " Results: [" . join(',', @results) . "]\n" .
- trim($sql) . "\n";
-}
-
-# True for a bug if we ran the "transform" function on it and the
-# result was equal to its first value.
-sub transformed_value_was_equal {
- my ($self, $number, $value) = @_;
- if (@_ > 2) {
- $self->{transformed_value_was_equal}->{$number} = $value;
- $self->search_test->was_equal_cache($self, $number, $value);
- }
- my $cached = $self->search_test->was_equal_cache($self, $number);
- return $cached if defined $cached;
- return $self->{transformed_value_was_equal}->{$number};
-}
-
-# True if this test is supposed to contain the numbered bug.
-sub bug_is_contained {
- my ($self, $number) = @_;
- my $contains = $self->test->{contains};
- if ($self->transformed_value_was_equal($number)
- and !$self->test->{override}->{$self->field}->{contains})
- {
- $contains = $self->test->{if_equal}->{contains};
- }
- return grep($_ == $number, @$contains) ? 1 : 0;
-}
-
-###################################################
-# Accessors: Ways of doing SKIP and TODO on tests #
-###################################################
-
-# The tests we know are broken for this operator/field combination.
-sub _known_broken {
- my ($self, $constant, $skip_pg_check) = @_;
-
- $constant ||= KNOWN_BROKEN;
- my $field = $self->field;
- my $type = $self->field_object->type;
- my $operator = $self->operator;
- my $value = $self->main_value;
- my $value_name = "$operator-$value";
- if (my $extra_name = $self->test->{extra_name}) {
- $value_name .= "-$extra_name";
- }
-
- my $value_broken = $constant->{$value_name}->{$field};
- $value_broken ||= $constant->{$value_name}->{$type};
- return $value_broken if $value_broken;
- my $operator_broken = $constant->{$operator}->{$field};
- $operator_broken ||= $constant->{$operator}->{$type};
- return $operator_broken if $operator_broken;
- return {};
-}
-
-# True if the "contains" search for the numbered bug is broken.
-# That is, either the result is supposed to contain it and doesn't,
-# or the result is not supposed to contain it and does.
-sub contains_known_broken {
- my ($self, $number) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
-
- my $contains_broken = $self->_known_broken->{contains} || [];
- if (grep($_ == $number, @$contains_broken)) {
- return "$field $operator contains $number is known to be broken";
- }
- return undef;
-}
-
-# Used by subclasses. Checks both bug_is_contained and contains_known_broken
-# to tell you whether or not the bug will *actually* be found by the test.
-sub will_actually_contain_bug {
- my ($self, $number) = @_;
- my $is_contained = $self->bug_is_contained($number) ? 1 : 0;
- my $is_broken = $self->contains_known_broken($number) ? 1 : 0;
-
- # If the test is supposed to contain the bug and *isn't* broken,
- # then the test will contain the bug.
- return 1 if ($is_contained and !$is_broken);
- # If this test is *not* supposed to contain the bug, but that test is
- # broken, then this test *will* contain the bug.
- return 1 if (!$is_contained and $is_broken);
-
- return 0;
-}
-
-# Returns a string if creating a Bugzilla::Search object throws an error,
-# with this field/operator/value combination.
-sub search_known_broken {
- my ($self) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
- if ($self->_known_broken->{search}) {
- return "Bugzilla::Search for $field $operator is known to be broken";
- }
- return undef;
-}
-
-# Returns a string if we haven't yet implemented the tests for this field,
-# but we plan to in the future.
-sub field_not_yet_implemented {
- my ($self) = @_;
- my $skip_this_field = grep { $_ eq $self->field } SKIP_FIELDS;
- if ($skip_this_field) {
- my $field = $self->field;
- return "$field testing not yet implemented";
- }
- return undef;
-}
-
-# Returns a message if this field/operator combination can't ever be run.
-# At no time in the future will this field/operator combination ever work.
-sub invalid_field_operator_combination {
- my ($self) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
-
- if ($field eq 'content' && $operator !~ /matches/) {
- return "content field does not support $operator";
- }
- elsif ($operator =~ /matches/ && $field ne 'content') {
- return "matches operator does not support fields other than content";
- }
- return undef;
-}
-
-# True if this field is broken in an OR combination.
-sub join_broken {
- my ($self, $or_broken_map) = @_;
- my $or_broken = $or_broken_map->{$self->field . '-' . $self->operator};
- if (!$or_broken) {
- # See if this is a comment field, and in that case, if there's
- # a generic entry for all comment fields.
- my $is_comment_field = COMMENT_FIELDS->{$self->field};
- if ($is_comment_field) {
- $or_broken = $or_broken_map->{'longdescs.-' . $self->operator};
- }
- }
- return $or_broken;
-}
-
-#########################################
-# Accessors: Bugzilla::Search Arguments #
-#########################################
-
-# The data that will get passed to Bugzilla::Search as its arguments.
-sub search_params {
- my ($self) = @_;
- return $self->{search_params} if $self->{search_params};
-
- my %params = (
- "field0-0-0" => $self->field,
- "type0-0-0" => $self->operator,
- "value0-0-0" => $self->translated_value,
- );
-
- $self->{search_params} = \%params;
- return $self->{search_params};
-}
-
-sub search_columns {
- my ($self) = @_;
- my $field = $self->field;
- my @search_fields = qw(bug_id);
- if ($self->field_object->buglist) {
- my $col_name = COLUMN_TRANSLATION->{$field} || $field;
- push(@search_fields, $col_name);
- }
- return \@search_fields;
-}
-
-
-################
-# Field Values #
-################
-
-sub _field_values_for_bug {
- my ($self, $number) = @_;
- my $field = $self->field;
-
- my @values;
-
- if ($field =~ /^attach.+\.(.+)$/ ) {
- my $attach_field = $1;
- $attach_field = ATTACHMENT_FIELDS->{$attach_field} || $attach_field;
- @values = $self->_values_for($number, 'attachments', $attach_field);
- }
- elsif (my $flag_field = FLAG_FIELDS->{$field}) {
- @values = $self->_values_for($number, 'flags', $flag_field);
- }
- elsif (my $translation = COMMENT_FIELDS->{$field}) {
- @values = $self->_values_for($number, 'comments', $translation);
- # We want the last value to come first, so that single-value
- # searches use the last comment.
- @values = reverse @values;
- }
- elsif ($field eq 'longdescs.count') {
- @values = scalar(@{ $self->bug($number)->comments });
- }
- elsif ($field eq 'work_time') {
- @values = $self->_values_for($number, 'actual_time');
- }
- elsif ($field eq 'bug_group') {
- @values = $self->_values_for($number, 'groups_in', 'name');
- }
- elsif ($field eq 'keywords') {
- @values = $self->_values_for($number, 'keyword_objects', 'name');
- }
- elsif ($field eq 'content') {
- @values = $self->_values_for($number, 'short_desc');
- }
- elsif ($field eq 'see_also') {
- @values = $self->_values_for($number, 'see_also', 'name');
- }
- elsif ($field eq 'tag') {
- @values = $self->_values_for($number, 'tags');
- }
- # Bugzilla::Bug truncates creation_ts, but we need the full value
- # from the database. This has no special value for changedfrom,
- # because it never changes.
- elsif ($field eq 'creation_ts') {
- my $bug = $self->bug($number);
- my $creation_ts = Bugzilla->dbh->selectrow_array(
- 'SELECT creation_ts FROM bugs WHERE bug_id = ?',
- undef, $bug->id);
- @values = ($creation_ts);
- }
- else {
- @values = $self->_values_for($number, $field);
- }
-
- # We convert user objects to their login name, here, all in one
- # block for simplicity.
- if (grep { $_ eq $field } USER_FIELDS) {
- # requestees.login_name is empty for most bugs (but checking
- # blessed(undef) handles that.
- # Values that come from %original_values aren't User objects.
- @values = map { blessed($_) ? $_->login : $_ } @values;
- @values = grep { defined $_ } @values;
- }
-
- return \@values;
-}
-
-sub _values_for {
- my ($self, $number, $bug_field, $item_field) = @_;
-
- my $item;
- if ($self->operator eq 'changedfrom') {
- $item = $self->search_test->bug_create_value($number, $bug_field);
- }
- else {
- my $bug = $self->bug($number);
- $item = $bug->$bug_field;
- }
-
- if ($item_field) {
- if ($bug_field eq 'flags' and $item_field eq 'name') {
- return (map { $_->name . $_->status } @$item);
- }
- return (map { $self->_get_item($_, $item_field) } @$item);
- }
-
- return @$item if ref($item) eq 'ARRAY';
- return $item if defined $item;
- return ();
-}
-
-sub _get_item {
- my ($self, $from, $field) = @_;
- if (blessed($from)) {
- return $from->$field;
- }
- return $from->{$field};
-}
-
-#####################
-# Value Translation #
-#####################
-
-# This function translates the "value" specified in TESTS into an actual
-# search value to pass to Search.pm. This means that we get the value
-# from the current bug (or, in the case of changedfrom, from %original_values)
-# and then we insert it as required into the "value" from TESTS. (For example,
-# <1> becomes the value for the field from bug 1.)
-sub _translate_value {
- my $self = shift;
- my $value = $self->test_value;
- foreach my $number (1..NUM_BUGS) {
- $value = $self->_translate_value_for_bug($number, $value);
- }
- # Sanity check to make sure that none of the <> stuff was left in.
- if ($value =~ /<\d/) {
- die $self->name . ": value untranslated: $value\n";
- }
- return $value;
-}
-
-sub _translate_value_for_bug {
- my ($self, $number, $value) = @_;
-
- my $bug = $self->bug($number);
-
- my $bug_id = $bug->id;
- $value =~ s/<$number-id>/$bug_id/g;
- my $bug_delta = $bug->delta_ts;
- $value =~ s/<$number-delta>/$bug_delta/g;
- my $reporter = $bug->reporter->login;
- $value =~ s/<$number-reporter>/$reporter/g;
- if ($value =~ /<$number-bug_group>/) {
- my @bug_groups = map { $_->name } @{ $bug->groups_in };
- @bug_groups = grep { $_ =~ /^\d+-group-/ } @bug_groups;
- my $group = $bug_groups[0];
- $value =~ s/<$number-bug_group>/$group/g;
- }
-
- my @bug_values = $self->bug_values($number);
- return $value if !@bug_values;
-
- if ($self->operator =~ /substr/) {
- @bug_values = map { $self->_substr_value($_) } @bug_values;
- }
-
- my $string_value = $bug_values[0];
- if ($self->operator =~ /word/) {
- $string_value = join(' ', @bug_values);
- }
- if (my $func = $self->test->{transform}) {
- my $transformed = $func->(@bug_values);
- my $is_equal = $transformed eq $bug_values[0] ? 1 : 0;
- $self->transformed_value_was_equal($number, $is_equal);
- $string_value = $transformed;
- }
-
- if ($self->test->{escape}) {
- $string_value = quotemeta($string_value);
- }
- $value =~ s/<$number>/$string_value/g;
-
- return $value;
-}
-
-sub _substr_value {
- my ($self, $value) = @_;
- my $field = $self->field;
- my $type = $self->field_object->type;
- my $substr_size = SUBSTR_SIZE;
- if (exists FIELD_SUBSTR_SIZE->{$field}) {
- $substr_size = FIELD_SUBSTR_SIZE->{$field};
- }
- elsif (exists FIELD_SUBSTR_SIZE->{$type}) {
- $substr_size = FIELD_SUBSTR_SIZE->{$type};
- }
- if ($substr_size > 0) {
- # The field name is included in every field value, and if it's
- # long, it might take up the whole substring, and we don't want that.
- if (!grep { $_ eq $field or $_ eq $type } SUBSTR_NO_FIELD_ADD) {
- $substr_size += length($field);
- }
- my $string = substr($value, 0, $substr_size);
- return $string;
- }
- return substr($value, $substr_size);
-}
-
-#####################
-# Main Test Methods #
-#####################
-
-sub run {
- my ($self) = @_;
-
- my $invalid_combination = $self->invalid_field_operator_combination;
- my $field_not_implemented = $self->field_not_yet_implemented;
-
- SKIP: {
- skip($invalid_combination, $self->num_tests) if $invalid_combination;
- TODO: {
- todo_skip ($field_not_implemented, $self->num_tests) if $field_not_implemented;
- $self->do_tests();
- }
- }
-}
-
-sub do_tests {
- my ($self) = @_;
- my $name = $self->name;
-
- my $search_broken = $self->search_known_broken;
-
- my $search = $self->_test_search_object_creation();
-
- my $sql;
- TODO: {
- local $TODO = $search_broken if $search_broken;
- lives_ok { $sql = $search->_sql } "$name: generate SQL";
- }
-
- my $results;
- SKIP: {
- skip "Can't run SQL without any SQL", 1 if !defined $sql;
- $results = $self->_test_sql($search);
- }
-
- $self->_test_content($results, $sql);
-}
-
-sub _test_search_object_creation {
- my ($self) = @_;
- my $name = $self->name;
- my @args = (fields => $self->search_columns, params => $self->search_params);
- my $search;
- lives_ok { $search = new Bugzilla::Search(@args) }
- "$name: create search object";
- return $search;
-}
-
-sub _test_sql {
- my ($self, $search) = @_;
- my $name = $self->name;
- my $results;
- lives_ok { $results = $search->data } "$name: Run SQL Query"
- or diag($search->_sql);
- return $results;
-}
-
-sub _test_content {
- my ($self, $results, $sql) = @_;
-
- SKIP: {
- skip "Without results we can't test them", NUM_BUGS if !$results;
- foreach my $number (1..NUM_BUGS) {
- $self->_test_content_for_bug($number, $results, $sql);
- }
- }
-}
-
-sub _test_content_for_bug {
- my ($self, $number, $results, $sql) = @_;
- my $name = $self->name;
-
- my $contains_known_broken = $self->contains_known_broken($number);
-
- my %result_ids = map { $_->[0] => 1 } @$results;
- my $bug_id = $self->bug($number)->id;
-
- TODO: {
- local $TODO = $contains_known_broken if $contains_known_broken;
- if ($self->bug_is_contained($number)) {
- ok($result_ids{$bug_id},
- "$name: contains bug $number ($bug_id)")
- or diag $self->debug_fail($number, $results, $sql);
- }
- else {
- ok(!$result_ids{$bug_id},
- "$name: does not contain bug $number ($bug_id)")
- or diag $self->debug_fail($number, $results, $sql);
- }
- }
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm b/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm
deleted file mode 100644
index 888e7eb13..000000000
--- a/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm
+++ /dev/null
@@ -1,104 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This is the same as a FieldTest, except that it uses normal URL
-# parameters instead of Boolean Charts.
-package Bugzilla::Test::Search::FieldTestNormal;
-use strict;
-use warnings;
-use parent qw(Bugzilla::Test::Search::FieldTest);
-
-use Scalar::Util qw(blessed);
-
-use constant CH_OPERATOR => {
- changedafter => 'chfieldfrom',
- changedbefore => 'chfieldto',
- changedto => 'chfieldvalue',
-};
-
-use constant EMAIL_FIELDS => qw(assigned_to qa_contact cc reporter commenter);
-
-# Normally, we just clone a FieldTest because that's the best for performance,
-# overall--that way we don't have to translate the value again. However,
-# sometimes (like in Bugzilla::Test::Search's direct code) we just want
-# to create a FieldTestNormal.
-sub new {
- my $class = shift;
- my ($first_arg) = @_;
- if (blessed $first_arg
- and $first_arg->isa('Bugzilla::Test::Search::FieldTest'))
- {
- my $self = { %$first_arg };
- return bless $self, $class;
- }
- return $class->SUPER::new(@_);
-}
-
-sub name {
- my $self = shift;
- my $name = $self->SUPER::name(@_);
- return "$name (Normal Params)";
-}
-
-sub search_columns {
- my $self = shift;
- my $field = $self->field;
- # For the assigned_to, qa_contact, and reporter fields, have the
- # "Normal Params" test check that the _realname columns work
- # all by themselves.
- if (grep($_ eq $field, EMAIL_FIELDS) && $self->field_object->buglist) {
- return ['bug_id', "${field}_realname"]
- }
- return $self->SUPER::search_columns(@_);
-}
-
-sub search_params {
- my ($self) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
- my $value = $self->translated_value;
- if ($operator eq 'anyexact') {
- $value = [split ',', $value];
- }
-
- if (my $ch_param = CH_OPERATOR->{$operator}) {
- if ($field eq 'creation_ts') {
- $field = '[Bug creation]';
- }
- return { chfield => $field, $ch_param => $value };
- }
-
- if ($field eq 'delta_ts' and $operator eq 'greaterthaneq') {
- return { chfieldfrom => $value };
- }
- if ($field eq 'delta_ts' and $operator eq 'lessthaneq') {
- return { chfieldto => $value };
- }
-
- if ($field eq 'deadline' and $operator eq 'greaterthaneq') {
- return { deadlinefrom => $value };
- }
- if ($field eq 'deadline' and $operator eq 'lessthaneq') {
- return { deadlineto => $value };
- }
-
- if (grep { $_ eq $field } EMAIL_FIELDS) {
- $field = 'longdesc' if $field eq 'commenter';
- return {
- email1 => $value,
- "email${field}1" => 1,
- emailtype1 => $operator,
- # Used to do extra tests on special sorts of email* combinations.
- %{ $self->test->{extra_params} || {} },
- };
- }
-
- $field =~ s/\./_/g;
- return { $field => $value, "${field}_type" => $operator };
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/InjectionTest.pm b/xt/lib/Bugzilla/Test/Search/InjectionTest.pm
deleted file mode 100644
index 90eaabc78..000000000
--- a/xt/lib/Bugzilla/Test/Search/InjectionTest.pm
+++ /dev/null
@@ -1,77 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This module represents the SQL Injection tests that get run on a single
-# operator/field combination for Bugzilla::Test::Search.
-package Bugzilla::Test::Search::InjectionTest;
-use parent qw(Bugzilla::Test::Search::FieldTest);
-
-use strict;
-use warnings;
-use Bugzilla::Test::Search::Constants;
-use Test::Exception;
-
-sub num_tests { return NUM_SEARCH_TESTS }
-
-sub _known_broken {
- my ($self) = @_;
- my $operator_broken = INJECTION_BROKEN_OPERATOR->{$self->operator};
- # We don't want to auto-vivify $operator_broken and thus make it true.
- my @field_ok = $operator_broken ? @{ $operator_broken->{field_ok} || [] }
- : ();
- $operator_broken = undef if grep { $_ eq $self->field } @field_ok;
-
- my $field_broken = INJECTION_BROKEN_FIELD->{$self->field}
- || INJECTION_BROKEN_FIELD->{$self->field_object->type};
- # We don't want to auto-vivify $field_broken and thus make it true.
- my @operator_ok = $field_broken ? @{ $field_broken->{operator_ok} || [] }
- : ();
- $field_broken = undef if grep { $_ eq $self->operator } @operator_ok;
-
- return $operator_broken || $field_broken || {};
-}
-
-sub sql_error_ok { return $_[0]->_known_broken->{sql_error} }
-
-# Injection tests only skip fields on certain dbs.
-sub field_not_yet_implemented {
- my ($self) = @_;
- # We use the constant directly because we don't want operator_ok
- # or field_ok to stop us.
- my $broken = INJECTION_BROKEN_FIELD->{$self->field}
- || INJECTION_BROKEN_FIELD->{$self->field_object->type};
- my $skip_for_dbs = $broken->{db_skip};
- return undef if !$skip_for_dbs;
- my $dbh = Bugzilla->dbh;
- if (my ($skip) = grep { $dbh->isa("Bugzilla::DB::$_") } @$skip_for_dbs) {
- my $field = $self->field;
- return "$field injection testing is not supported with $skip";
- }
- return undef;
-}
-# Injection tests don't do translation.
-sub translated_value { $_[0]->test_value }
-
-sub name { return "injection-" . $_[0]->SUPER::name; }
-
-# Injection tests don't check content.
-sub _test_content {}
-
-sub _test_sql {
- my $self = shift;
- my ($sql) = @_;
- my $dbh = Bugzilla->dbh;
- my $name = $self->name;
- if (my $error_ok = $self->sql_error_ok) {
- throws_ok { $dbh->selectall_arrayref($sql) } $error_ok,
- "$name: SQL query dies, as we expect";
- return;
- }
- return $self->SUPER::_test_sql(@_);
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/NotTest.pm b/xt/lib/Bugzilla/Test/Search/NotTest.pm
deleted file mode 100644
index 190b8567b..000000000
--- a/xt/lib/Bugzilla/Test/Search/NotTest.pm
+++ /dev/null
@@ -1,61 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This module runs tests just like a normal FieldTest, AndTest,
-# or OrTest, but in a NOT chart instead of a normal chart.
-#
-# Logically this should be a mixin of some sort so that we can apply
-# it to OrTest and AndTest, but without Moose there isn't much of an
-# easy way to do that.
-package Bugzilla::Test::Search::NotTest;
-use parent qw(Bugzilla::Test::Search::FieldTest);
-use strict;
-use warnings;
-use Bugzilla::Test::Search::Constants;
-
-# We just clone a FieldTest because that's the best for performance,
-# overall--that way we don't have to translate the value again.
-sub new {
- my ($class, $field_test) = @_;
- my $self = { %$field_test };
- return bless $self, $class;
-}
-
-#############
-# Accessors #
-#############
-
-sub name {
- my ($self) = @_;
- return "NOT(" . $self->SUPER::name . ")";
-}
-
-# True if this test is supposed to contain the numbered bug. Reversed for
-# NOT tests.
-sub bug_is_contained {
- my $self = shift;
- my ($number) = @_;
- # No search ever returns bug 6, because it's protected by security groups
- # that the searcher isn't a member of.
- return 0 if $number == 6;
- return $self->SUPER::bug_is_contained(@_) ? 0 : 1;
-}
-
-# NOT tests have their own constant for tracking broken-ness.
-sub _known_broken {
- my ($self) = @_;
- return $self->SUPER::_known_broken(BROKEN_NOT, 'skip pg check');
-}
-
-sub search_params {
- my ($self) = @_;
- my %params = %{ $self->SUPER::search_params() };
- $params{negate0} = 1;
- return \%params;
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/OperatorTest.pm b/xt/lib/Bugzilla/Test/Search/OperatorTest.pm
deleted file mode 100644
index 5ab502dfc..000000000
--- a/xt/lib/Bugzilla/Test/Search/OperatorTest.pm
+++ /dev/null
@@ -1,103 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This module represents the tests that get run on a single operator
-# from the TESTS constant in Bugzilla::Search::Test::Constants.
-package Bugzilla::Test::Search::OperatorTest;
-
-use strict;
-use warnings;
-use Bugzilla::Test::Search::Constants;
-use Bugzilla::Test::Search::FieldTest;
-use Bugzilla::Test::Search::FieldTestNormal;
-use Bugzilla::Test::Search::InjectionTest;
-use Bugzilla::Test::Search::OrTest;
-use Bugzilla::Test::Search::AndTest;
-use Bugzilla::Test::Search::NotTest;
-
-###############
-# Constructor #
-###############
-
-sub new {
- my ($invocant, $operator, $search_test) = @_;
- $search_test ||= $invocant->search_test;
- my $class = ref($invocant) || $invocant;
- return bless { search_test => $search_test, operator => $operator }, $class;
-}
-
-#############
-# Accessors #
-#############
-
-# The Bugzilla::Test::Search object that this is a child of.
-sub search_test { return $_[0]->{search_test} }
-# The operator being tested
-sub operator { return $_[0]->{operator} }
-# The tests that we're going to run on this operator.
-sub tests { return @{ TESTS->{$_[0]->operator } } }
-# The fields we're going to test for this operator.
-sub test_fields { return $_[0]->search_test->all_fields }
-
-sub run {
- my ($self) = @_;
-
- foreach my $field ($self->test_fields) {
- foreach my $test ($self->tests) {
- my $field_test =
- new Bugzilla::Test::Search::FieldTest($self, $field, $test);
- $field_test->run();
- my $normal_test =
- new Bugzilla::Test::Search::FieldTestNormal($field_test);
- $normal_test->run();
- my $not_test = new Bugzilla::Test::Search::NotTest($field_test);
- $not_test->run();
-
- next if !$self->search_test->option('long');
-
- # Run the OR tests. This tests every other operator (including
- # this operator itself) in combination with every other field,
- # in an OR with this operator and field.
- foreach my $other_operator ($self->search_test->all_operators) {
- $self->run_join_tests($field_test, $other_operator);
- }
- }
- foreach my $test (INJECTION_TESTS) {
- my $injection_test =
- new Bugzilla::Test::Search::InjectionTest($self, $field, $test);
- $injection_test->run();
- }
- }
-}
-
-sub run_join_tests {
- my ($self, $field_test, $other_operator) = @_;
-
- my $other_operator_test = $self->new($other_operator);
- foreach my $other_test ($other_operator_test->tests) {
- foreach my $other_field ($self->test_fields) {
- $self->_run_one_join_test($field_test, $other_operator_test,
- $other_field, $other_test);
- $self->search_test->clean_test_history();
- }
- }
-}
-
-sub _run_one_join_test {
- my ($self, $field_test, $other_operator_test, $other_field, $other_test) = @_;
- my $other_field_test =
- new Bugzilla::Test::Search::FieldTest($other_operator_test,
- $other_field, $other_test);
- my $or_test = new Bugzilla::Test::Search::OrTest($field_test,
- $other_field_test);
- $or_test->run();
- my $and_test = new Bugzilla::Test::Search::AndTest($field_test,
- $other_field_test);
- $and_test->run();
-}
-
-1;
diff --git a/xt/lib/Bugzilla/Test/Search/OrTest.pm b/xt/lib/Bugzilla/Test/Search/OrTest.pm
deleted file mode 100644
index 1b948f38d..000000000
--- a/xt/lib/Bugzilla/Test/Search/OrTest.pm
+++ /dev/null
@@ -1,141 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# This Source Code Form is "Incompatible With Secondary Licenses", as
-# defined by the Mozilla Public License, v. 2.0.
-
-# This test combines two field/operator combinations using OR in
-# a single boolean chart.
-package Bugzilla::Test::Search::OrTest;
-use parent qw(Bugzilla::Test::Search::FieldTest);
-
-use Bugzilla::Test::Search::Constants;
-use List::MoreUtils qw(all any uniq);
-
-use constant type => 'OR';
-
-###############
-# Constructor #
-###############
-
-sub new {
- my $class = shift;
- my $self = { field_tests => [@_] };
- return bless $self, $class;
-}
-
-#############
-# Accessors #
-#############
-
-sub field_tests { return @{ $_[0]->{field_tests} } }
-sub search_test { ($_[0]->field_tests)[0]->search_test }
-
-sub name {
- my ($self) = @_;
- my @names = map { $_->name } $self->field_tests;
- return join('-' . $self->type . '-', @names);
-}
-
-# In an OR test, bugs ARE supposed to be contained if they are contained
-# by ANY test.
-sub bug_is_contained {
- my ($self, $number) = @_;
- return any { $_->bug_is_contained($number) } $self->field_tests;
-}
-
-# Needed only for failure messages
-sub debug_value {
- my ($self) = @_;
- my @values = map { $_->field . ' ' . $_->debug_value } $self->field_tests;
- return join(' ' . $self->type . ' ', @values);
-}
-
-########################
-# SKIP & TODO Messages #
-########################
-
-sub field_not_yet_implemented {
- my ($self) = @_;
- return $self->_join_messages('field_not_yet_implemented');
-}
-sub invalid_field_operator_combination {
- my ($self) = @_;
- return $self->_join_messages('invalid_field_operator_combination');
-}
-sub search_known_broken {
- my ($self) = @_;
- return $self->_join_messages('search_known_broken');
-}
-
-sub _join_messages {
- my ($self, $message_method) = @_;
- my @messages = map { $_->$message_method } $self->field_tests;
- @messages = grep { $_ } @messages;
- return join(' AND ', @messages);
-}
-
-sub _bug_will_actually_be_contained {
- my ($self, $number) = @_;
-
- foreach my $test ($self->field_tests) {
- # Some tests are broken in such a way that they actually
- # generate no criteria in the SQL. In this case, the only way
- # the test contains the bug is if *another* test contains it.
- next if $test->_known_broken->{no_criteria};
- return 1 if $test->will_actually_contain_bug($number);
- }
- return 0;
-}
-
-sub contains_known_broken {
- my ($self, $number) = @_;
-
- if ( ( $self->bug_is_contained($number)
- and !$self->_bug_will_actually_be_contained($number) )
- or ( !$self->bug_is_contained($number)
- and $self->_bug_will_actually_be_contained($number) ) )
- {
- my @messages = map { $_->contains_known_broken($number) }
- $self->field_tests;
- @messages = grep { $_ } @messages;
- # Sometimes, with things that break because of no_criteria, there won't
- # be anything in @messages even though we need to print out a message.
- if (!@messages) {
- my @no_criteria = grep { $_->_known_broken->{no_criteria} }
- $self->field_tests;
- @messages = map { "No criteria generated by " . $_->name }
- @no_criteria;
- }
- die "broken test with no message" if !@messages;
- return join(' AND ', @messages);
- }
- return undef;
-}
-
-##############################
-# Bugzilla::Search arguments #
-##############################
-
-sub search_columns {
- my ($self) = @_;
- my @columns = map { @{ $_->search_columns } } $self->field_tests;
- return [uniq @columns];
-}
-
-sub search_params {
- my ($self) = @_;
- my @all_params = map { $_->search_params } $self->field_tests;
- my %params;
- my $chart = 0;
- foreach my $item (@all_params) {
- $params{"field0-0-$chart"} = $item->{'field0-0-0'};
- $params{"type0-0-$chart"} = $item->{'type0-0-0'};
- $params{"value0-0-$chart"} = $item->{'value0-0-0'};
- $chart++;
- }
- return \%params;
-}
-
-1;