From 8ec8da0491ad89604700b3e29a227966f6d84ba1 Mon Sep 17 00:00:00 2001 From: Perl Tidy Date: Wed, 5 Dec 2018 15:38:52 -0500 Subject: no bug - reformat all the code using the new perltidy rules --- xt/lib/Bugzilla/Test/Search/Constants.pm | 1857 +++++++++++++++--------------- 1 file changed, 951 insertions(+), 906 deletions(-) (limited to 'xt/lib/Bugzilla/Test/Search/Constants.pm') diff --git a/xt/lib/Bugzilla/Test/Search/Constants.pm b/xt/lib/Bugzilla/Test/Search/Constants.pm index 53f8851fb..34953d697 100644 --- a/xt/lib/Bugzilla/Test/Search/Constants.pm +++ b/xt/lib/Bugzilla/Test/Search/Constants.pm @@ -31,28 +31,28 @@ 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 + 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 @@ -77,6 +77,7 @@ 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; @@ -88,40 +89,37 @@ 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', + 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', + 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', + longdesc => 'body', + commenter => 'author', + 'longdescs.isprivate' => 'is_private', }; # Same as above, for Bugzilla::Attachment. -use constant ATTACHMENT_FIELDS => { - mimetype => 'contenttype', - submitter => 'attacher', - thedata => 'data', -}; +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', + 'flagtypes.name' => 'name', + 'setters.login_name' => 'setter', + 'requestees.login_name' => 'requestee', }; # These are fields that we don't test. Test::More will mark these @@ -129,40 +127,43 @@ use constant FLAG_FIELDS => { # # We don't support days_elapsed or owner_idle_time yet. use constant SKIP_FIELDS => qw( - owner_idle_time - days_elapsed + 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 + 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, + 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 @@ -170,9 +171,9 @@ use constant FIELD_SUBSTR_SIZE => { # 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 + target_milestone remaining_time percentage_complete work_time + attachments.mimetype attachments.submitter attachments.filename + attachments.description flagtypes.name ); ################ @@ -192,42 +193,42 @@ use constant SUBSTR_NO_FIELD_ADD => FIELD_TYPE_DATETIME, qw( # 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] }, -); +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] }, + + # 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] }, + 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] }, + 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]}, ); @@ -252,114 +253,94 @@ use constant CHANGED_VALUE_BROKEN => ( # while the other fails. In this case, we have a special override for # "operator-value", which uniquely identifies tests. use constant KNOWN_BROKEN => { - "equals-%group.<1-bug_group>%" => { - commenter => { contains => [1,2,3,4,5] }, - }, - - 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] }, - }, + "equals-%group.<1-bug_group>%" => {commenter => {contains => [1, 2, 3, 4, 5]},}, + + 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]},}, }; ################### @@ -368,135 +349,90 @@ use constant KNOWN_BROKEN => { # 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] }, + "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] }, + '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] }, - }, + 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]},}, }; ############# @@ -507,113 +443,117 @@ use constant BROKEN_NOT => { # 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' } + '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] }, + 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] }, + 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] }, + '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] }, + '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, + '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 => [] }, + 'attachments.submitter' => {contains => []}, + bug_id => {contains => []}, + reporter => {contains => []}, + tag => {contains => []}, ); ######### @@ -673,298 +613,326 @@ use constant CHANGED_OVERRIDE => ( # 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] }, - }, - }, - ], + 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]}, + }, + }, + ], }; # Fields that do not behave as we expect, for InjectionTest. @@ -973,57 +941,62 @@ use constant TESTS => { # 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)], - }, + + # 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 }, + changedafter => {search => 1, field_ok => ['creation_ts']}, + changedbefore => {search => 1, field_ok => ['creation_ts']}, + changedby => {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' } + {value => ';SEMICOLON_TEST'}, + {value => '--COMMENT_TEST'}, + {value => "'QUOTE_TEST"}, + {value => "';QUOTE_SEMICOLON_TEST"}, + {value => '/*STAR_COMMENT_TEST'} ); ################# @@ -1031,185 +1004,257 @@ use constant INJECTION_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] }, + { + 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>' }, - ] - }, + { + 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>'}, + ] + }, ); -- cgit v1.2.3-24-g4f1b