aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xt/lib/Bugzilla/Test')
-rw-r--r--xt/lib/Bugzilla/Test/Search.pm1495
-rw-r--r--xt/lib/Bugzilla/Test/Search/AndTest.pm30
-rw-r--r--xt/lib/Bugzilla/Test/Search/Constants.pm1834
-rw-r--r--xt/lib/Bugzilla/Test/Search/CustomTest.pm81
-rw-r--r--xt/lib/Bugzilla/Test/Search/FieldTest.pm832
-rw-r--r--xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm129
-rw-r--r--xt/lib/Bugzilla/Test/Search/InjectionTest.pm80
-rw-r--r--xt/lib/Bugzilla/Test/Search/NotTest.pm35
-rw-r--r--xt/lib/Bugzilla/Test/Search/OperatorTest.pm103
-rw-r--r--xt/lib/Bugzilla/Test/Search/OrTest.pm139
10 files changed, 2436 insertions, 2322 deletions
diff --git a/xt/lib/Bugzilla/Test/Search.pm b/xt/lib/Bugzilla/Test/Search.pm
index ca3bba5cf..31ba8bea3 100644
--- a/xt/lib/Bugzilla/Test/Search.pm
+++ b/xt/lib/Bugzilla/Test/Search.pm
@@ -59,8 +59,8 @@ use Scalar::Util qw(blessed);
###############
sub new {
- my ($class, $options) = @_;
- return bless { options => $options }, $class;
+ my ($class, $options) = @_;
+ return bless {options => $options}, $class;
}
#############
@@ -68,198 +68,210 @@ sub new {
#############
sub options { return $_[0]->{options} }
-sub option { return $_[0]->{options}->{$_[1]} }
+sub option { return $_[0]->{options}->{$_[1]} }
sub num_tests {
- my ($self) = @_;
- my @top_operators = $self->top_level_operators;
- my @all_operators = $self->all_operators;
- my $top_operator_tests = $self->_total_operator_tests(\@top_operators);
- my $all_operator_tests = $self->_total_operator_tests(\@all_operators);
-
- my @fields = $self->all_fields;
-
- # Basically, we run TESTS_PER_RUN tests for each field/operator combination.
- my $top_combinations = $top_operator_tests * scalar(@fields);
- my $all_combinations = $all_operator_tests * scalar(@fields);
- # But we also have ORs, for which we run combinations^2 tests.
- my $join_tests = $self->option('long')
- ? ($top_combinations * $all_combinations) : 0;
- # And AND tests, which means we run 2x $join_tests;
- $join_tests = $join_tests * 2;
- # Also, because of NOT tests and Normal tests, we run 3x $top_combinations.
- my $basic_tests = $top_combinations * 3;
- my $operator_field_tests = ($basic_tests + $join_tests) * TESTS_PER_RUN;
-
- # Then we test each field/operator combination for SQL injection.
- my @injection_values = INJECTION_TESTS;
- my $sql_injection_tests = scalar(@fields) * scalar(@top_operators)
- * scalar(@injection_values) * NUM_SEARCH_TESTS;
-
- # This @{ [] } thing is the only reasonable way to get a count out of a
- # constant array.
- my $special_tests = scalar(@{ [SPECIAL_PARAM_TESTS, CUSTOM_SEARCH_TESTS] })
- * TESTS_PER_RUN;
-
- return $operator_field_tests + $sql_injection_tests + $special_tests;
+ my ($self) = @_;
+ my @top_operators = $self->top_level_operators;
+ my @all_operators = $self->all_operators;
+ my $top_operator_tests = $self->_total_operator_tests(\@top_operators);
+ my $all_operator_tests = $self->_total_operator_tests(\@all_operators);
+
+ my @fields = $self->all_fields;
+
+ # Basically, we run TESTS_PER_RUN tests for each field/operator combination.
+ my $top_combinations = $top_operator_tests * scalar(@fields);
+ my $all_combinations = $all_operator_tests * scalar(@fields);
+
+ # But we also have ORs, for which we run combinations^2 tests.
+ my $join_tests
+ = $self->option('long') ? ($top_combinations * $all_combinations) : 0;
+
+ # And AND tests, which means we run 2x $join_tests;
+ $join_tests = $join_tests * 2;
+
+ # Also, because of NOT tests and Normal tests, we run 3x $top_combinations.
+ my $basic_tests = $top_combinations * 3;
+ my $operator_field_tests = ($basic_tests + $join_tests) * TESTS_PER_RUN;
+
+ # Then we test each field/operator combination for SQL injection.
+ my @injection_values = INJECTION_TESTS;
+ my $sql_injection_tests
+ = scalar(@fields)
+ * scalar(@top_operators)
+ * scalar(@injection_values)
+ * NUM_SEARCH_TESTS;
+
+ # This @{ [] } thing is the only reasonable way to get a count out of a
+ # constant array.
+ my $special_tests
+ = scalar(@{[SPECIAL_PARAM_TESTS, CUSTOM_SEARCH_TESTS]}) * TESTS_PER_RUN;
+
+ return $operator_field_tests + $sql_injection_tests + $special_tests;
}
sub _total_operator_tests {
- my ($self, $operators) = @_;
-
- # Some operators have more than one test. Find those ones and add
- # them to the total operator tests
- my $extra_operator_tests;
- foreach my $operator (@$operators) {
- my $tests = TESTS->{$operator};
- next if !$tests;
- my $extra_num = scalar(@$tests) - 1;
- $extra_operator_tests += $extra_num;
- }
- return scalar(@$operators) + $extra_operator_tests;
-
+ my ($self, $operators) = @_;
+
+ # Some operators have more than one test. Find those ones and add
+ # them to the total operator tests
+ my $extra_operator_tests;
+ foreach my $operator (@$operators) {
+ my $tests = TESTS->{$operator};
+ next if !$tests;
+ my $extra_num = scalar(@$tests) - 1;
+ $extra_operator_tests += $extra_num;
+ }
+ return scalar(@$operators) + $extra_operator_tests;
+
}
sub all_operators {
- my ($self) = @_;
- if (not $self->{all_operators}) {
-
- my @operators;
- if (my $limit_operators = $self->option('operators')) {
- @operators = split(',', $limit_operators);
- }
- else {
- @operators = sort (keys %{ Bugzilla::Search::OPERATORS() });
- }
- # "substr" is just a backwards-compatibility operator, same as "substring".
- @operators = grep { $_ ne 'substr' } @operators;
- $self->{all_operators} = \@operators;
+ my ($self) = @_;
+ if (not $self->{all_operators}) {
+
+ my @operators;
+ if (my $limit_operators = $self->option('operators')) {
+ @operators = split(',', $limit_operators);
}
- return @{ $self->{all_operators} };
+ else {
+ @operators = sort (keys %{Bugzilla::Search::OPERATORS()});
+ }
+
+ # "substr" is just a backwards-compatibility operator, same as "substring".
+ @operators = grep { $_ ne 'substr' } @operators;
+ $self->{all_operators} = \@operators;
+ }
+ return @{$self->{all_operators}};
}
sub all_fields {
- my $self = shift;
- if (not $self->{all_fields}) {
- $self->_create_custom_fields();
- my @fields = @{ Bugzilla->fields };
- @fields = sort { $a->name cmp $b->name } @fields;
- $self->{all_fields} = \@fields;
- }
- return @{ $self->{all_fields} };
+ my $self = shift;
+ if (not $self->{all_fields}) {
+ $self->_create_custom_fields();
+ my @fields = @{Bugzilla->fields};
+ @fields = sort { $a->name cmp $b->name } @fields;
+ $self->{all_fields} = \@fields;
+ }
+ return @{$self->{all_fields}};
}
sub top_level_operators {
- my ($self) = @_;
- if (!$self->{top_level_operators}) {
- my @operators;
- my $limit_top = $self->option('top-operators');
- if ($limit_top) {
- @operators = split(',', $limit_top);
- }
- else {
- @operators = $self->all_operators;
- }
- $self->{top_level_operators} = \@operators;
+ my ($self) = @_;
+ if (!$self->{top_level_operators}) {
+ my @operators;
+ my $limit_top = $self->option('top-operators');
+ if ($limit_top) {
+ @operators = split(',', $limit_top);
+ }
+ else {
+ @operators = $self->all_operators;
}
- return @{ $self->{top_level_operators} };
+ $self->{top_level_operators} = \@operators;
+ }
+ return @{$self->{top_level_operators}};
}
sub text_fields {
- my ($self) = @_;
- my @text_fields = grep { $_->type == FIELD_TYPE_TEXTAREA
- or $_->type == FIELD_TYPE_FREETEXT } $self->all_fields;
- @text_fields = map { $_->name } @text_fields;
- push(@text_fields, qw(short_desc status_whiteboard bug_file_loc see_also));
- return @text_fields;
+ my ($self) = @_;
+ my @text_fields
+ = grep { $_->type == FIELD_TYPE_TEXTAREA or $_->type == FIELD_TYPE_FREETEXT }
+ $self->all_fields;
+ @text_fields = map { $_->name } @text_fields;
+ push(@text_fields, qw(short_desc status_whiteboard bug_file_loc see_also));
+ return @text_fields;
}
sub bugs {
- my $self = shift;
- $self->{bugs} ||= [map { $self->_create_one_bug($_) } (1..NUM_BUGS)];
- return @{ $self->{bugs} };
+ my $self = shift;
+ $self->{bugs} ||= [map { $self->_create_one_bug($_) } (1 .. NUM_BUGS)];
+ return @{$self->{bugs}};
}
# Get a numbered bug.
sub bug {
- my ($self, $number) = @_;
- return ($self->bugs)[$number - 1];
+ my ($self, $number) = @_;
+ return ($self->bugs)[$number - 1];
}
sub admin {
- my $self = shift;
- if (!$self->{admin_user}) {
- my $admin = create_user("admin");
- Bugzilla::Install::make_admin($admin);
- $self->{admin_user} = $admin;
- }
- # We send back a fresh object every time, to make sure that group
- # memberships are always up-to-date.
- return new Bugzilla::User($self->{admin_user}->id);
+ my $self = shift;
+ if (!$self->{admin_user}) {
+ my $admin = create_user("admin");
+ Bugzilla::Install::make_admin($admin);
+ $self->{admin_user} = $admin;
+ }
+
+ # We send back a fresh object every time, to make sure that group
+ # memberships are always up-to-date.
+ return new Bugzilla::User($self->{admin_user}->id);
}
sub nobody {
- my $self = shift;
- $self->{nobody} ||= Bugzilla::Group->create({ name => "nobody-" . random(),
- description => "Nobody", isbuggroup => 1 });
- return $self->{nobody};
+ my $self = shift;
+ $self->{nobody} ||= Bugzilla::Group->create(
+ {name => "nobody-" . random(), description => "Nobody", isbuggroup => 1});
+ return $self->{nobody};
}
+
sub everybody {
- my ($self) = @_;
- $self->{everybody} ||= create_group('To The Limit');
- return $self->{everybody};
+ my ($self) = @_;
+ $self->{everybody} ||= create_group('To The Limit');
+ return $self->{everybody};
}
sub bug_create_value {
- my ($self, $number, $field) = @_;
- $field = $field->name if blessed($field);
- if ($number == 6 and $field ne 'alias') {
- $number = 1;
- }
- my $extra_values = $self->_extra_bug_create_values->{$number};
- if (exists $extra_values->{$field}) {
- return $extra_values->{$field};
- }
- return $self->_bug_create_values->{$number}->{$field};
+ my ($self, $number, $field) = @_;
+ $field = $field->name if blessed($field);
+ if ($number == 6 and $field ne 'alias') {
+ $number = 1;
+ }
+ my $extra_values = $self->_extra_bug_create_values->{$number};
+ if (exists $extra_values->{$field}) {
+ return $extra_values->{$field};
+ }
+ return $self->_bug_create_values->{$number}->{$field};
}
+
sub bug_update_value {
- my ($self, $number, $field) = @_;
- $field = $field->name if blessed($field);
- if ($number == 6 and $field ne 'alias') {
- $number = 1;
- }
- return $self->_bug_update_values->{$number}->{$field};
+ my ($self, $number, $field) = @_;
+ $field = $field->name if blessed($field);
+ if ($number == 6 and $field ne 'alias') {
+ $number = 1;
+ }
+ return $self->_bug_update_values->{$number}->{$field};
}
# Values used to create the bugs.
sub _bug_create_values {
- my $self = shift;
- return $self->{bug_create_values} if $self->{bug_create_values};
- my %values;
- foreach my $number (1..NUM_BUGS) {
- $values{$number} = $self->_create_field_values($number, 'for create');
- }
- $self->{bug_create_values} = \%values;
- return $self->{bug_create_values};
+ my $self = shift;
+ return $self->{bug_create_values} if $self->{bug_create_values};
+ my %values;
+ foreach my $number (1 .. NUM_BUGS) {
+ $values{$number} = $self->_create_field_values($number, 'for create');
+ }
+ $self->{bug_create_values} = \%values;
+ return $self->{bug_create_values};
}
+
# Values as they existed on the bug, at creation time. Used by the
# changedfrom tests.
sub _extra_bug_create_values {
- my $self = shift;
- $self->{extra_bug_create_values} ||= { map { $_ => {} } (1..NUM_BUGS) };
- return $self->{extra_bug_create_values};
+ my $self = shift;
+ $self->{extra_bug_create_values} ||= {map { $_ => {} } (1 .. NUM_BUGS)};
+ return $self->{extra_bug_create_values};
}
# Values used to update the bugs after they are created.
sub _bug_update_values {
- my $self = shift;
- return $self->{bug_update_values} if $self->{bug_update_values};
- my %values;
- foreach my $number (1..NUM_BUGS) {
- $values{$number} = $self->_create_field_values($number);
- }
- $self->{bug_update_values} = \%values;
- return $self->{bug_update_values};
+ my $self = shift;
+ return $self->{bug_update_values} if $self->{bug_update_values};
+ my %values;
+ foreach my $number (1 .. NUM_BUGS) {
+ $values{$number} = $self->_create_field_values($number);
+ }
+ $self->{bug_update_values} = \%values;
+ return $self->{bug_update_values};
}
##############################
@@ -267,8 +279,8 @@ sub _bug_update_values {
##############################
sub random {
- $_[0] ||= FIELD_SIZE;
- generate_random_password(@_);
+ $_[0] ||= FIELD_SIZE;
+ generate_random_password(@_);
}
# We need to use a custom timestamp for each create() and update(),
@@ -276,53 +288,52 @@ sub random {
# for the entire transaction, and we need each created bug to have
# its own creation_ts and delta_ts.
sub timestamp {
- my ($day, $second) = @_;
- return DateTime->new(
- year => 2037,
- month => 1,
- day => $day,
- hour => 12,
- minute => $second,
- second => 0,
- # We make it floating because the timezone doesn't matter for our uses,
- # and we want totally consistent behavior across all possible machines.
- time_zone => 'floating',
- );
+ my ($day, $second) = @_;
+ return DateTime->new(
+ year => 2037,
+ month => 1,
+ day => $day,
+ hour => 12,
+ minute => $second,
+ second => 0,
+
+ # We make it floating because the timezone doesn't matter for our uses,
+ # and we want totally consistent behavior across all possible machines.
+ time_zone => 'floating',
+ );
}
sub create_keyword {
- my ($number) = @_;
- return Bugzilla::Keyword->create({
- name => "$number-keyword-" . random(),
- description => "Keyword $number" });
+ my ($number) = @_;
+ return Bugzilla::Keyword->create(
+ {name => "$number-keyword-" . random(), description => "Keyword $number"});
}
sub create_user {
- my ($prefix) = @_;
- my $user_name = $prefix . '-' . random(15) . "@" . random(12)
- . "." . random(3);
- my $user_realname = $prefix . '-' . random();
- my $user = Bugzilla::User->create({
- login_name => $user_name,
- realname => $user_realname,
- cryptpassword => '*',
- });
- return $user;
+ my ($prefix) = @_;
+ my $user_name = $prefix . '-' . random(15) . "@" . random(12) . "." . random(3);
+ my $user_realname = $prefix . '-' . random();
+ my $user = Bugzilla::User->create(
+ {login_name => $user_name, realname => $user_realname, cryptpassword => '*',});
+ return $user;
}
sub create_group {
- my ($prefix) = @_;
- return Bugzilla::Group->create({
- name => "$prefix-group-" . random(), description => "Everybody $prefix",
- userregexp => '.*', isbuggroup => 1 });
+ my ($prefix) = @_;
+ return Bugzilla::Group->create({
+ name => "$prefix-group-" . random(),
+ description => "Everybody $prefix",
+ userregexp => '.*',
+ isbuggroup => 1
+ });
}
sub create_legal_value {
- my ($field, $number) = @_;
- my $type = Bugzilla::Field::Choice->type($field);
- my $field_name = $field->name;
- return $type->create({ value => "$number-$field_name-" . random(),
- is_open => 0 });
+ my ($field, $number) = @_;
+ my $type = Bugzilla::Field::Choice->type($field);
+ my $field_name = $field->name;
+ return $type->create(
+ {value => "$number-$field_name-" . random(), is_open => 0});
}
#########################
@@ -330,22 +341,22 @@ sub create_legal_value {
#########################
sub _create_custom_fields {
- my ($self) = @_;
- return if !$self->option('add-custom-fields');
-
- while (my ($type, $name) = each %{ CUSTOM_FIELDS() }) {
- my $exists = new Bugzilla::Field({ name => $name });
- next if $exists;
- Bugzilla::Field->create({
- name => $name,
- type => $type,
- description => "Search Test Field $name",
- enter_bug => 1,
- custom => 1,
- buglist => 1,
- is_mandatory => 0,
- });
- }
+ my ($self) = @_;
+ return if !$self->option('add-custom-fields');
+
+ while (my ($type, $name) = each %{CUSTOM_FIELDS()}) {
+ my $exists = new Bugzilla::Field({name => $name});
+ next if $exists;
+ Bugzilla::Field->create({
+ name => $name,
+ type => $type,
+ description => "Search Test Field $name",
+ enter_bug => 1,
+ custom => 1,
+ buglist => 1,
+ is_mandatory => 0,
+ });
+ }
}
########################
@@ -353,221 +364,232 @@ sub _create_custom_fields {
########################
sub _create_field_values {
- my ($self, $number, $for_create) = @_;
- my $dbh = Bugzilla->dbh;
-
- Bugzilla->set_user($self->admin);
-
- my @selects = grep { $_->is_select } $self->all_fields;
- my %values;
- foreach my $field (@selects) {
- next if $field->is_abnormal;
- $values{$field->name} = create_legal_value($field, $number)->name;
- }
-
- my $group = create_group($number);
- $values{groups} = [$group->name];
-
- $values{'keywords'} = create_keyword($number)->name;
-
- foreach my $field (qw(assigned_to qa_contact reporter cc)) {
- $values{$field} = create_user("$number-$field")->login;
- }
-
- my $classification = Bugzilla::Classification->create(
- { name => "$number-classification-" . random() });
- $classification = $classification->name;
-
- my $version = "$number-version-" . random();
- my $milestone = "$number-tm-" . random(15);
- my $product = Bugzilla::Product->create({
- name => "$number-product-" . random(),
- description => 'Created by t/search.t',
- defaultmilestone => $milestone,
- classification => $classification,
- version => $version,
- allows_unconfirmed => 1,
- });
- foreach my $item ($group, $self->nobody) {
- $product->set_group_controls($item,
- { membercontrol => CONTROLMAPSHOWN,
- othercontrol => CONTROLMAPNA });
- }
- # $product->update() is called lower down.
- my $component = Bugzilla::Component->create({
- product => $product, name => "$number-component-" . random(),
- initialowner => create_user("$number-defaultowner")->login,
- initialqacontact => create_user("$number-defaultqa")->login,
- initial_cc => [create_user("$number-initcc")->login],
- description => "Component $number" });
-
- $values{'product'} = $product->name;
- $values{'component'} = $component->name;
- $values{'target_milestone'} = $milestone;
- $values{'version'} = $version;
-
- foreach my $field ($self->text_fields) {
- # We don't add a - after $field for the text fields, because
- # if we do, fulltext searching for short_desc pulls out
- # "short_desc" as a word and matches it in every bug.
- my $value = "$number-$field" . random();
- if ($field eq 'bug_file_loc' or $field eq 'see_also') {
- $value = "http://$value-" . random(3)
- . "/show_bug.cgi?id=$number";
- }
- $values{$field} = $value;
- }
- $values{'tag'} = ["$number-tag-" . random()];
-
- my @date_fields = grep { $_->type == FIELD_TYPE_DATETIME } $self->all_fields;
- foreach my $field (@date_fields) {
- # We use 03 as the month because that differs from our creation_ts,
- # delta_ts, and deadline. (It's nice to have recognizable values
- # for each field when debugging.)
- my $second = $for_create ? $number : $number + 1;
- $values{$field->name} = "2037-03-0$number 12:34:0$second";
+ my ($self, $number, $for_create) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ Bugzilla->set_user($self->admin);
+
+ my @selects = grep { $_->is_select } $self->all_fields;
+ my %values;
+ foreach my $field (@selects) {
+ next if $field->is_abnormal;
+ $values{$field->name} = create_legal_value($field, $number)->name;
+ }
+
+ my $group = create_group($number);
+ $values{groups} = [$group->name];
+
+ $values{'keywords'} = create_keyword($number)->name;
+
+ foreach my $field (qw(assigned_to qa_contact reporter cc)) {
+ $values{$field} = create_user("$number-$field")->login;
+ }
+
+ my $classification = Bugzilla::Classification->create(
+ {name => "$number-classification-" . random()});
+ $classification = $classification->name;
+
+ my $version = "$number-version-" . random();
+ my $milestone = "$number-tm-" . random(15);
+ my $product = Bugzilla::Product->create({
+ name => "$number-product-" . random(),
+ description => 'Created by t/search.t',
+ defaultmilestone => $milestone,
+ classification => $classification,
+ version => $version,
+ allows_unconfirmed => 1,
+ });
+ foreach my $item ($group, $self->nobody) {
+ $product->set_group_controls($item,
+ {membercontrol => CONTROLMAPSHOWN, othercontrol => CONTROLMAPNA});
+ }
+
+ # $product->update() is called lower down.
+ my $component = Bugzilla::Component->create({
+ product => $product,
+ name => "$number-component-" . random(),
+ initialowner => create_user("$number-defaultowner")->login,
+ initialqacontact => create_user("$number-defaultqa")->login,
+ initial_cc => [create_user("$number-initcc")->login],
+ description => "Component $number"
+ });
+
+ $values{'product'} = $product->name;
+ $values{'component'} = $component->name;
+ $values{'target_milestone'} = $milestone;
+ $values{'version'} = $version;
+
+ foreach my $field ($self->text_fields) {
+
+ # We don't add a - after $field for the text fields, because
+ # if we do, fulltext searching for short_desc pulls out
+ # "short_desc" as a word and matches it in every bug.
+ my $value = "$number-$field" . random();
+ if ($field eq 'bug_file_loc' or $field eq 'see_also') {
+ $value = "http://$value-" . random(3) . "/show_bug.cgi?id=$number";
}
-
- $values{alias} = "$number-alias-" . random(12);
-
- # Prefixing the original comment with "description" makes the
- # lesserthan and greaterthan tests behave predictably.
- my $comm_prefix = $for_create ? "description-" : '';
- $values{comment} = "$comm_prefix$number-comment-" . random()
- . ' ' . random();
-
- my @flags;
- my $setter = create_user("$number-setters.login_name");
- my $requestee = create_user("$number-requestees.login_name");
- $values{set_flags} = _create_flags($number, $setter, $requestee);
-
- my $month = $for_create ? "12" : "02";
- $values{'deadline'} = "2037-$month-0$number";
- my $estimate_times = $for_create ? 10 : 1;
- $values{estimated_time} = $estimate_times * $number;
-
- $values{attachment} = _get_attach_values($number, $for_create);
-
- # Some things only happen on the first bug.
- if ($number == 1) {
- # We use 6 as the prefix for the extra values, because bug 6's values
- # don't otherwise get used (since bug 6 is created as a clone of
- # bug 1). This also makes sure that our greaterthan/lessthan
- # tests work properly.
- my $extra_group = create_group(6);
- $product->set_group_controls($extra_group,
- { membercontrol => CONTROLMAPSHOWN,
- othercontrol => CONTROLMAPNA });
- $values{groups} = [$values{groups}->[0], $extra_group->name];
- my $extra_keyword = create_keyword(6);
- $values{keywords} = [$values{keywords}, $extra_keyword->name];
- my $extra_cc = create_user("6-cc");
- $values{cc} = [$values{cc}, $extra_cc->login];
- my @multi_selects = grep { $_->type == FIELD_TYPE_MULTI_SELECT }
- $self->all_fields;
- foreach my $field (@multi_selects) {
- my $new_value = create_legal_value($field, 6);
- my $name = $field->name;
- $values{$name} = [$values{$name}, $new_value->name];
- }
- push(@{ $values{'tag'} }, "6-tag-" . random());
+ $values{$field} = $value;
+ }
+ $values{'tag'} = ["$number-tag-" . random()];
+
+ my @date_fields = grep { $_->type == FIELD_TYPE_DATETIME } $self->all_fields;
+ foreach my $field (@date_fields) {
+
+ # We use 03 as the month because that differs from our creation_ts,
+ # delta_ts, and deadline. (It's nice to have recognizable values
+ # for each field when debugging.)
+ my $second = $for_create ? $number : $number + 1;
+ $values{$field->name} = "2037-03-0$number 12:34:0$second";
+ }
+
+ $values{alias} = "$number-alias-" . random(12);
+
+ # Prefixing the original comment with "description" makes the
+ # lesserthan and greaterthan tests behave predictably.
+ my $comm_prefix = $for_create ? "description-" : '';
+ $values{comment} = "$comm_prefix$number-comment-" . random() . ' ' . random();
+
+ my @flags;
+ my $setter = create_user("$number-setters.login_name");
+ my $requestee = create_user("$number-requestees.login_name");
+ $values{set_flags} = _create_flags($number, $setter, $requestee);
+
+ my $month = $for_create ? "12" : "02";
+ $values{'deadline'} = "2037-$month-0$number";
+ my $estimate_times = $for_create ? 10 : 1;
+ $values{estimated_time} = $estimate_times * $number;
+
+ $values{attachment} = _get_attach_values($number, $for_create);
+
+ # Some things only happen on the first bug.
+ if ($number == 1) {
+
+ # We use 6 as the prefix for the extra values, because bug 6's values
+ # don't otherwise get used (since bug 6 is created as a clone of
+ # bug 1). This also makes sure that our greaterthan/lessthan
+ # tests work properly.
+ my $extra_group = create_group(6);
+ $product->set_group_controls($extra_group,
+ {membercontrol => CONTROLMAPSHOWN, othercontrol => CONTROLMAPNA});
+ $values{groups} = [$values{groups}->[0], $extra_group->name];
+ my $extra_keyword = create_keyword(6);
+ $values{keywords} = [$values{keywords}, $extra_keyword->name];
+ my $extra_cc = create_user("6-cc");
+ $values{cc} = [$values{cc}, $extra_cc->login];
+ my @multi_selects
+ = grep { $_->type == FIELD_TYPE_MULTI_SELECT } $self->all_fields;
+
+ foreach my $field (@multi_selects) {
+ my $new_value = create_legal_value($field, 6);
+ my $name = $field->name;
+ $values{$name} = [$values{$name}, $new_value->name];
}
-
- # On bug 5, any field that *can* be left empty, *is* left empty.
- if ($number == 5) {
- my @set_fields = grep { $_->type == FIELD_TYPE_SINGLE_SELECT }
- $self->all_fields;
- @set_fields = map { $_->name } @set_fields;
- push(@set_fields, qw(short_desc version reporter));
- foreach my $key (keys %values) {
- delete $values{$key} unless grep { $_ eq $key } @set_fields;
- }
+ push(@{$values{'tag'}}, "6-tag-" . random());
+ }
+
+ # On bug 5, any field that *can* be left empty, *is* left empty.
+ if ($number == 5) {
+ my @set_fields
+ = grep { $_->type == FIELD_TYPE_SINGLE_SELECT } $self->all_fields;
+ @set_fields = map { $_->name } @set_fields;
+ push(@set_fields, qw(short_desc version reporter));
+ foreach my $key (keys %values) {
+ delete $values{$key} unless grep { $_ eq $key } @set_fields;
}
+ }
- $product->update();
+ $product->update();
- return \%values;
+ return \%values;
}
# Flags
sub _create_flags {
- my ($number, $setter, $requestee) = @_;
+ my ($number, $setter, $requestee) = @_;
- my $flagtypes = _create_flagtypes($number);
+ my $flagtypes = _create_flagtypes($number);
- my %flags;
- foreach my $type (qw(a b)) {
- $flags{$type} = _get_flag_values(@_, $flagtypes->{$type});
- }
- return \%flags;
+ my %flags;
+ foreach my $type (qw(a b)) {
+ $flags{$type} = _get_flag_values(@_, $flagtypes->{$type});
+ }
+ return \%flags;
}
sub _create_flagtypes {
- my ($number) = @_;
- my $dbh = Bugzilla->dbh;
- my $name = "$number-flag-" . random();
- my $desc = "FlagType $number";
-
- my %flagtypes;
- foreach my $target (qw(a b)) {
- $dbh->do("INSERT INTO flagtypes
+ my ($number) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $name = "$number-flag-" . random();
+ my $desc = "FlagType $number";
+
+ my %flagtypes;
+ foreach my $target (qw(a b)) {
+ $dbh->do(
+ "INSERT INTO flagtypes
(name, description, target_type, is_requestable,
is_requesteeble, is_multiplicable, cc_list)
- VALUES (?,?,?,1,1,1,'')",
- undef, $name, $desc, $target);
- my $id = $dbh->bz_last_key('flagtypes', 'id');
- $dbh->do('INSERT INTO flaginclusions (type_id) VALUES (?)',
- undef, $id);
- my $flagtype = new Bugzilla::FlagType($id);
- $flagtypes{$target} = $flagtype;
- }
- return \%flagtypes;
+ VALUES (?,?,?,1,1,1,'')", undef, $name, $desc, $target
+ );
+ my $id = $dbh->bz_last_key('flagtypes', 'id');
+ $dbh->do('INSERT INTO flaginclusions (type_id) VALUES (?)', undef, $id);
+ my $flagtype = new Bugzilla::FlagType($id);
+ $flagtypes{$target} = $flagtype;
+ }
+ return \%flagtypes;
}
sub _get_flag_values {
- my ($number, $setter, $requestee, $flagtype) = @_;
-
- my @set_flags;
- if ($number <= 2) {
- foreach my $value (qw(? - + ?)) {
- my $flag = { type_id => $flagtype->id, status => $value,
- setter => $setter, flagtype => $flagtype };
- push(@set_flags, $flag);
- }
- $set_flags[0]->{requestee} = $requestee->login;
+ my ($number, $setter, $requestee, $flagtype) = @_;
+
+ my @set_flags;
+ if ($number <= 2) {
+ foreach my $value (qw(? - + ?)) {
+ my $flag = {
+ type_id => $flagtype->id,
+ status => $value,
+ setter => $setter,
+ flagtype => $flagtype
+ };
+ push(@set_flags, $flag);
}
- else {
- @set_flags = ({ type_id => $flagtype->id, status => '+',
- setter => $setter, flagtype => $flagtype });
- }
- return \@set_flags;
+ $set_flags[0]->{requestee} = $requestee->login;
+ }
+ else {
+ @set_flags = ({
+ type_id => $flagtype->id,
+ status => '+',
+ setter => $setter,
+ flagtype => $flagtype
+ });
+ }
+ return \@set_flags;
}
# Attachments
sub _get_attach_values {
- my ($number, $for_create) = @_;
-
- my $boolean = $number == 1 ? 1 : 0;
- if ($for_create) {
- $boolean = !$boolean ? 1 : 0;
- }
- my $ispatch = $for_create ? 'ispatch' : 'is_patch';
- my $isobsolete = $for_create ? 'isobsolete' : 'is_obsolete';
- my $isprivate = $for_create ? 'isprivate' : 'is_private';
- my $mimetype = $for_create ? 'mimetype' : 'content_type';
-
- my %values = (
- description => "$number-attach_desc-" . random(),
- filename => "$number-filename-" . random(),
- $ispatch => $boolean,
- $isobsolete => $boolean,
- $isprivate => $boolean,
- $mimetype => "text/x-$number-" . random(),
- );
- if ($for_create) {
- $values{data} = "$number-data-" . random() . random();
- }
- return \%values;
+ my ($number, $for_create) = @_;
+
+ my $boolean = $number == 1 ? 1 : 0;
+ if ($for_create) {
+ $boolean = !$boolean ? 1 : 0;
+ }
+ my $ispatch = $for_create ? 'ispatch' : 'is_patch';
+ my $isobsolete = $for_create ? 'isobsolete' : 'is_obsolete';
+ my $isprivate = $for_create ? 'isprivate' : 'is_private';
+ my $mimetype = $for_create ? 'mimetype' : 'content_type';
+
+ my %values = (
+ description => "$number-attach_desc-" . random(),
+ filename => "$number-filename-" . random(),
+ $ispatch => $boolean,
+ $isobsolete => $boolean,
+ $isprivate => $boolean,
+ $mimetype => "text/x-$number-" . random(),
+ );
+ if ($for_create) {
+ $values{data} = "$number-data-" . random() . random();
+ }
+ return \%values;
}
################
@@ -575,194 +597,205 @@ sub _get_attach_values {
################
sub _create_one_bug {
- my ($self, $number) = @_;
- my $dbh = Bugzilla->dbh;
-
- # We need bug 6 to have a unique alias that is not a clone of bug 1's,
- # so we get the alias separately from the other parameters.
- my $alias = $self->bug_create_value($number, 'alias');
- my $update_alias = $self->bug_update_value($number, 'alias');
-
- # Otherwise, make bug 6 a clone of bug 1.
- my $real_number = $number;
- $number = 1 if $number == 6;
-
- my $reporter = $self->bug_create_value($number, 'reporter');
- Bugzilla->set_user(Bugzilla::User->check($reporter));
-
- # We create the bug with one set of values, and then we change it
- # to have different values.
- my %params = %{ $self->_bug_create_values->{$number} };
- $params{alias} = $alias;
-
- # There are some things in bug_create_values that shouldn't go into
- # create().
- delete @params{qw(attachment set_flags tag)};
-
- my ($status, $resolution, $see_also) =
- delete @params{qw(bug_status resolution see_also)};
- # All the bugs are created with everconfirmed = 0.
- $params{bug_status} = 'UNCONFIRMED';
- my $bug = Bugzilla::Bug->create(\%params);
-
- # These are necessary for the changedfrom tests.
- my $extra_values = $self->_extra_bug_create_values->{$number};
- foreach my $field (qw(comments remaining_time percentage_complete
- keyword_objects everconfirmed dependson blocked
- groups_in classification actual_time))
- {
- $extra_values->{$field} = $bug->$field;
+ my ($self, $number) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ # We need bug 6 to have a unique alias that is not a clone of bug 1's,
+ # so we get the alias separately from the other parameters.
+ my $alias = $self->bug_create_value($number, 'alias');
+ my $update_alias = $self->bug_update_value($number, 'alias');
+
+ # Otherwise, make bug 6 a clone of bug 1.
+ my $real_number = $number;
+ $number = 1 if $number == 6;
+
+ my $reporter = $self->bug_create_value($number, 'reporter');
+ Bugzilla->set_user(Bugzilla::User->check($reporter));
+
+ # We create the bug with one set of values, and then we change it
+ # to have different values.
+ my %params = %{$self->_bug_create_values->{$number}};
+ $params{alias} = $alias;
+
+ # There are some things in bug_create_values that shouldn't go into
+ # create().
+ delete @params{qw(attachment set_flags tag)};
+
+ my ($status, $resolution, $see_also)
+ = delete @params{qw(bug_status resolution see_also)};
+
+ # All the bugs are created with everconfirmed = 0.
+ $params{bug_status} = 'UNCONFIRMED';
+ my $bug = Bugzilla::Bug->create(\%params);
+
+ # These are necessary for the changedfrom tests.
+ my $extra_values = $self->_extra_bug_create_values->{$number};
+ foreach my $field (qw(comments remaining_time percentage_complete
+ keyword_objects everconfirmed dependson blocked
+ groups_in classification actual_time))
+ {
+ $extra_values->{$field} = $bug->$field;
+ }
+ $extra_values->{reporter_accessible} = $number == 1 ? 0 : 1;
+ $extra_values->{cclist_accessible} = $number == 1 ? 0 : 1;
+
+ if ($number == 5) {
+
+ # Bypass Bugzilla::Bug--we don't want any changes in bugs_activity
+ # for bug 5.
+ $dbh->do(
+ 'UPDATE bugs SET qa_contact = NULL, reporter_accessible = 0,
+ cclist_accessible = 0 WHERE bug_id = ?', undef,
+ $bug->id
+ );
+ $dbh->do('DELETE FROM cc WHERE bug_id = ?', undef, $bug->id);
+ my $ts = '1970-01-01 00:00:00';
+ $dbh->do(
+ 'UPDATE bugs SET creation_ts = ?, delta_ts = ?
+ WHERE bug_id = ?', undef, $ts, $ts, $bug->id
+ );
+ $dbh->do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
+ undef, $ts, $bug->id);
+ $bug->{creation_ts} = $ts;
+ $extra_values->{see_also} = [];
+ }
+ else {
+ # Manually set the creation_ts so that each bug has a different one.
+ #
+ # Also, manually update the resolution and bug_status, because
+ # we want to see both of them change in bugs_activity, so we
+ # have to start with values for both (and as of the time when I'm
+ # writing this test, Bug->create doesn't support setting resolution).
+ #
+ # Same for see_also.
+ my $timestamp = timestamp($number, $number - 1);
+ my $creation_ts = $timestamp->ymd . ' ' . $timestamp->hms;
+ $bug->{creation_ts} = $creation_ts;
+ $dbh->do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
+ undef, $creation_ts, $bug->id);
+ $dbh->do(
+ 'UPDATE bugs SET creation_ts = ?, bug_status = ?,
+ resolution = ? WHERE bug_id = ?', undef, $creation_ts, $status,
+ $resolution, $bug->id
+ );
+ $dbh->do('INSERT INTO bug_see_also (bug_id, value, class) VALUES (?,?,?)',
+ undef, $bug->id, $see_also, 'Bugzilla::BugUrl::Bugzilla');
+ $extra_values->{see_also} = $bug->see_also;
+
+ # All the tags must be created as the admin user, so that the
+ # admin user can find them, later.
+ my $original_user = Bugzilla->user;
+ Bugzilla->set_user($self->admin);
+ my $tags = $self->bug_create_value($number, 'tag');
+ $bug->add_tag($_) foreach @$tags;
+ $extra_values->{tags} = $tags;
+ Bugzilla->set_user($original_user);
+
+ if ($number == 1) {
+
+ # Bug 1 needs to start off with reporter_accessible and
+ # cclist_accessible being 0, so that when we change them to 1,
+ # that change shows up in bugs_activity.
+ $dbh->do(
+ 'UPDATE bugs SET reporter_accessible = 0,
+ cclist_accessible = 0 WHERE bug_id = ?', undef, $bug->id
+ );
+
+ # Bug 1 gets three comments, so that longdescs.count matches it
+ # uniquely. The third comment is added in the middle, so that the
+ # last comment contains all of the important data, like work_time.
+ $bug->add_comment("1-comment-" . random(100));
}
- $extra_values->{reporter_accessible} = $number == 1 ? 0 : 1;
- $extra_values->{cclist_accessible} = $number == 1 ? 0 : 1;
-
- if ($number == 5) {
- # Bypass Bugzilla::Bug--we don't want any changes in bugs_activity
- # for bug 5.
- $dbh->do('UPDATE bugs SET qa_contact = NULL, reporter_accessible = 0,
- cclist_accessible = 0 WHERE bug_id = ?',
- undef, $bug->id);
- $dbh->do('DELETE FROM cc WHERE bug_id = ?', undef, $bug->id);
- my $ts = '1970-01-01 00:00:00';
- $dbh->do('UPDATE bugs SET creation_ts = ?, delta_ts = ?
- WHERE bug_id = ?', undef, $ts, $ts, $bug->id);
- $dbh->do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
- undef, $ts, $bug->id);
- $bug->{creation_ts} = $ts;
- $extra_values->{see_also} = [];
+
+ my %update_params = %{$self->_bug_update_values->{$number}};
+ my %reverse_map = reverse %{Bugzilla::Bug->FIELD_MAP};
+ foreach my $db_name (keys %reverse_map) {
+ next if $db_name eq 'comment';
+ next if $db_name eq 'status_whiteboard';
+ if (exists $update_params{$db_name}) {
+ my $update_name = $reverse_map{$db_name};
+ $update_params{$update_name} = delete $update_params{$db_name};
+ }
}
- else {
- # Manually set the creation_ts so that each bug has a different one.
- #
- # Also, manually update the resolution and bug_status, because
- # we want to see both of them change in bugs_activity, so we
- # have to start with values for both (and as of the time when I'm
- # writing this test, Bug->create doesn't support setting resolution).
- #
- # Same for see_also.
- my $timestamp = timestamp($number, $number - 1);
- my $creation_ts = $timestamp->ymd . ' ' . $timestamp->hms;
- $bug->{creation_ts} = $creation_ts;
- $dbh->do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
- undef, $creation_ts, $bug->id);
- $dbh->do('UPDATE bugs SET creation_ts = ?, bug_status = ?,
- resolution = ? WHERE bug_id = ?',
- undef, $creation_ts, $status, $resolution, $bug->id);
- $dbh->do('INSERT INTO bug_see_also (bug_id, value, class) VALUES (?,?,?)',
- undef, $bug->id, $see_also, 'Bugzilla::BugUrl::Bugzilla');
- $extra_values->{see_also} = $bug->see_also;
-
- # All the tags must be created as the admin user, so that the
- # admin user can find them, later.
- my $original_user = Bugzilla->user;
- Bugzilla->set_user($self->admin);
- my $tags = $self->bug_create_value($number, 'tag');
- $bug->add_tag($_) foreach @$tags;
- $extra_values->{tags} = $tags;
- Bugzilla->set_user($original_user);
-
- if ($number == 1) {
- # Bug 1 needs to start off with reporter_accessible and
- # cclist_accessible being 0, so that when we change them to 1,
- # that change shows up in bugs_activity.
- $dbh->do('UPDATE bugs SET reporter_accessible = 0,
- cclist_accessible = 0 WHERE bug_id = ?',
- undef, $bug->id);
- # Bug 1 gets three comments, so that longdescs.count matches it
- # uniquely. The third comment is added in the middle, so that the
- # last comment contains all of the important data, like work_time.
- $bug->add_comment("1-comment-" . random(100));
- }
-
- my %update_params = %{ $self->_bug_update_values->{$number} };
- my %reverse_map = reverse %{ Bugzilla::Bug->FIELD_MAP };
- foreach my $db_name (keys %reverse_map) {
- next if $db_name eq 'comment';
- next if $db_name eq 'status_whiteboard';
- if (exists $update_params{$db_name}) {
- my $update_name = $reverse_map{$db_name};
- $update_params{$update_name} = delete $update_params{$db_name};
- }
- }
-
- my ($new_status, $new_res) =
- delete @update_params{qw(status resolution)};
- # Bypass the status workflow.
- $bug->{bug_status} = $new_status;
- $bug->{resolution} = $new_res;
- $bug->{everconfirmed} = 1 if $number == 1;
-
- # add/remove/set fields.
- $update_params{keywords} = { set => $update_params{keywords} };
- $update_params{groups} = { add => $update_params{groups},
- remove => $bug->groups_in };
- my @cc_remove = map { $_->login } @{ $bug->cc_users };
- my $cc_new = $update_params{cc};
- my @cc_add = ref($cc_new) ? @$cc_new : ($cc_new);
- # We make the admin an explicit CC on bug 1 (but not on bug 6), so
- # that we can test the %user% pronoun properly.
- if ($real_number == 1) {
- push(@cc_add, $self->admin->login);
- }
- $update_params{cc} = { add => \@cc_add, remove => \@cc_remove };
- my $see_also_remove = $bug->see_also;
- my $see_also_add = [$update_params{see_also}];
- $update_params{see_also} = { add => $see_also_add,
- remove => $see_also_remove };
- $update_params{comment} = { body => $update_params{comment} };
- $update_params{work_time} = $number;
- # Setting work_time kills the remaining_time, so we need to
- # preserve that. We add 8 because that produces an integer
- # percentage_complete for bug 1, which is necessary for
- # accurate "equals"-type searching.
- $update_params{remaining_time} = $number + 8;
- $update_params{reporter_accessible} = $number == 1 ? 1 : 0;
- $update_params{cclist_accessible} = $number == 1 ? 1 : 0;
- $update_params{alias} = $update_alias;
-
- $bug->set_all(\%update_params);
- my $flags = $self->bug_create_value($number, 'set_flags')->{b};
- $bug->set_flags([], $flags);
- $timestamp->set(second => $number);
- $bug->update($timestamp->ymd . ' ' . $timestamp->hms);
- $extra_values->{flags} = $bug->flags;
-
- # It's not generally safe to do update() multiple times on
- # the same Bug object.
- $bug = new Bugzilla::Bug($bug->id);
- my $update_flags = $self->bug_update_value($number, 'set_flags')->{b};
- $_->{status} = 'X' foreach @{ $bug->flags };
- $bug->set_flags($bug->flags, $update_flags);
- if ($number == 1) {
- my $comment_id = $bug->comments->[-1]->id;
- $bug->set_comment_is_private({ $comment_id => 1 });
- }
- $bug->update($bug->delta_ts);
-
- my $attach_create = $self->bug_create_value($number, 'attachment');
- my $attachment = Bugzilla::Attachment->create({
- bug => $bug,
- creation_ts => $creation_ts,
- %$attach_create });
- # Store for the changedfrom tests.
- $extra_values->{attachments} =
- [new Bugzilla::Attachment($attachment->id)];
-
- my $attach_update = $self->bug_update_value($number, 'attachment');
- $attachment->set_all($attach_update);
- # In order to keep the mimetype on the ispatch attachment,
- # we need to bypass the validator.
- $attachment->{mimetype} = $attach_update->{content_type};
- my $attach_flags = $self->bug_update_value($number, 'set_flags')->{a};
- $attachment->set_flags([], $attach_flags);
- $attachment->update($bug->delta_ts);
+
+ my ($new_status, $new_res) = delete @update_params{qw(status resolution)};
+
+ # Bypass the status workflow.
+ $bug->{bug_status} = $new_status;
+ $bug->{resolution} = $new_res;
+ $bug->{everconfirmed} = 1 if $number == 1;
+
+ # add/remove/set fields.
+ $update_params{keywords} = {set => $update_params{keywords}};
+ $update_params{groups}
+ = {add => $update_params{groups}, remove => $bug->groups_in};
+ my @cc_remove = map { $_->login } @{$bug->cc_users};
+ my $cc_new = $update_params{cc};
+ my @cc_add = ref($cc_new) ? @$cc_new : ($cc_new);
+
+ # We make the admin an explicit CC on bug 1 (but not on bug 6), so
+ # that we can test the %user% pronoun properly.
+ if ($real_number == 1) {
+ push(@cc_add, $self->admin->login);
+ }
+ $update_params{cc} = {add => \@cc_add, remove => \@cc_remove};
+ my $see_also_remove = $bug->see_also;
+ my $see_also_add = [$update_params{see_also}];
+ $update_params{see_also} = {add => $see_also_add, remove => $see_also_remove};
+ $update_params{comment} = {body => $update_params{comment}};
+ $update_params{work_time} = $number;
+
+ # Setting work_time kills the remaining_time, so we need to
+ # preserve that. We add 8 because that produces an integer
+ # percentage_complete for bug 1, which is necessary for
+ # accurate "equals"-type searching.
+ $update_params{remaining_time} = $number + 8;
+ $update_params{reporter_accessible} = $number == 1 ? 1 : 0;
+ $update_params{cclist_accessible} = $number == 1 ? 1 : 0;
+ $update_params{alias} = $update_alias;
+
+ $bug->set_all(\%update_params);
+ my $flags = $self->bug_create_value($number, 'set_flags')->{b};
+ $bug->set_flags([], $flags);
+ $timestamp->set(second => $number);
+ $bug->update($timestamp->ymd . ' ' . $timestamp->hms);
+ $extra_values->{flags} = $bug->flags;
+
+ # It's not generally safe to do update() multiple times on
+ # the same Bug object.
+ $bug = new Bugzilla::Bug($bug->id);
+ my $update_flags = $self->bug_update_value($number, 'set_flags')->{b};
+ $_->{status} = 'X' foreach @{$bug->flags};
+ $bug->set_flags($bug->flags, $update_flags);
+ if ($number == 1) {
+ my $comment_id = $bug->comments->[-1]->id;
+ $bug->set_comment_is_private({$comment_id => 1});
}
-
- # Values for changedfrom.
- $extra_values->{creation_ts} = $bug->creation_ts;
- $extra_values->{delta_ts} = $bug->creation_ts;
-
- return new Bugzilla::Bug($bug->id);
+ $bug->update($bug->delta_ts);
+
+ my $attach_create = $self->bug_create_value($number, 'attachment');
+ my $attachment = Bugzilla::Attachment->create(
+ {bug => $bug, creation_ts => $creation_ts, %$attach_create});
+
+ # Store for the changedfrom tests.
+ $extra_values->{attachments} = [new Bugzilla::Attachment($attachment->id)];
+
+ my $attach_update = $self->bug_update_value($number, 'attachment');
+ $attachment->set_all($attach_update);
+
+ # In order to keep the mimetype on the ispatch attachment,
+ # we need to bypass the validator.
+ $attachment->{mimetype} = $attach_update->{content_type};
+ my $attach_flags = $self->bug_update_value($number, 'set_flags')->{a};
+ $attachment->set_flags([], $attach_flags);
+ $attachment->update($bug->delta_ts);
+ }
+
+ # Values for changedfrom.
+ $extra_values->{creation_ts} = $bug->creation_ts;
+ $extra_values->{delta_ts} = $bug->creation_ts;
+
+ return new Bugzilla::Bug($bug->id);
}
###################################
@@ -778,44 +811,45 @@ sub _create_one_bug {
# field, which we store more efficiently, in an array, and then we re-populate
# the Test_Results in Test::Builder at the end of the test.
sub clean_test_history {
- my ($self) = @_;
- return if !$self->option('long');
- my $builder = Test::More->builder;
- my $current_test = $builder->current_test;
-
- # I don't use details() because I don't want to copy the array.
- my $results = $builder->{Test_Results};
- my $check_test = $current_test - 1;
- while (my $result = $results->[$check_test]) {
- last if !$result;
- $self->test_success($check_test, $result->{ok});
- $check_test--;
- }
-
- # Truncate the test history array, but retain the current test number.
- $builder->{Test_Results} = [];
- $builder->{Curr_Test} = $current_test;
+ my ($self) = @_;
+ return if !$self->option('long');
+ my $builder = Test::More->builder;
+ my $current_test = $builder->current_test;
+
+ # I don't use details() because I don't want to copy the array.
+ my $results = $builder->{Test_Results};
+ my $check_test = $current_test - 1;
+ while (my $result = $results->[$check_test]) {
+ last if !$result;
+ $self->test_success($check_test, $result->{ok});
+ $check_test--;
+ }
+
+ # Truncate the test history array, but retain the current test number.
+ $builder->{Test_Results} = [];
+ $builder->{Curr_Test} = $current_test;
}
sub test_success {
- my ($self, $index, $status) = @_;
- $self->{test_success}->[$index] = $status;
- return $self->{test_success};
+ my ($self, $index, $status) = @_;
+ $self->{test_success}->[$index] = $status;
+ return $self->{test_success};
}
sub repopulate_test_results {
- my ($self) = @_;
- return if !$self->option('long');
- $self->clean_test_history();
- # We create only two hashes, for memory efficiency.
- my %ok = ( ok => 1 );
- my %not_ok = ( ok => 0 );
- my @results;
- foreach my $success (@{ $self->{test_success} }) {
- push(@results, $success ? \%ok : \%not_ok);
- }
- my $builder = Test::More->builder;
- $builder->{Test_Results} = \@results;
+ my ($self) = @_;
+ return if !$self->option('long');
+ $self->clean_test_history();
+
+ # We create only two hashes, for memory efficiency.
+ my %ok = (ok => 1);
+ my %not_ok = (ok => 0);
+ my @results;
+ foreach my $success (@{$self->{test_success}}) {
+ push(@results, $success ? \%ok : \%not_ok);
+ }
+ my $builder = Test::More->builder;
+ $builder->{Test_Results} = \@results;
}
##########
@@ -828,13 +862,13 @@ sub repopulate_test_results {
# have to re-run the value-translation code every time (which can be pretty
# slow).
sub value_translation_cache {
- my ($self, $field_test, $value) = @_;
- return if !$self->option('long');
- my $test_name = $field_test->name;
- if (@_ == 3) {
- $self->{value_translation_cache}->{$test_name} = $value;
- }
- return $self->{value_translation_cache}->{$test_name};
+ my ($self, $field_test, $value) = @_;
+ return if !$self->option('long');
+ my $test_name = $field_test->name;
+ if (@_ == 3) {
+ $self->{value_translation_cache}->{$test_name} = $value;
+ }
+ return $self->{value_translation_cache}->{$test_name};
}
# When doing AND/OR tests, the value for transformed_value_was_equal
@@ -842,13 +876,13 @@ sub value_translation_cache {
# if we pull our values from the value_translation_cache. So we need
# to also cache the values for transformed_value_was_equal.
sub was_equal_cache {
- my ($self, $field_test, $number, $value) = @_;
- return if !$self->option('long');
- my $test_name = $field_test->name;
- if (@_ == 4) {
- $self->{tvwe_cache}->{$test_name}->{$number} = $value;
- }
- return $self->{tvwe_cache}->{$test_name}->{$number};
+ my ($self, $field_test, $number, $value) = @_;
+ return if !$self->option('long');
+ my $test_name = $field_test->name;
+ if (@_ == 4) {
+ $self->{tvwe_cache}->{$test_name}->{$number} = $value;
+ }
+ return $self->{tvwe_cache}->{$test_name}->{$number};
}
#############
@@ -856,132 +890,135 @@ sub was_equal_cache {
#############
sub run {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
-
- # We want backtraces on any "die" message or any warning.
- # Otherwise it's hard to trace errors inside of Bugzilla::Search from
- # reading automated test run results.
- local $SIG{__WARN__} = \&Carp::cluck;
- local $SIG{__DIE__} = \&Carp::confess;
-
- $dbh->bz_start_transaction();
-
- # Some parameters need to be set in order for the tests to function
- # properly.
- my $everybody = $self->everybody;
- my $params = Bugzilla->params;
- local $params->{'useclassification'} = 1;
- local $params->{'useqacontact'} = 1;
- local $params->{'usetargetmilestone'} = 1;
- local $params->{'mail_delivery_method'} = 'None';
- local $params->{'timetrackinggroup'} = $everybody->name;
- local $params->{'insidergroup'} = $everybody->name;
-
- $self->_setup_bugs();
-
- # Even though _setup_bugs set us as an admin, we want to be sure at
- # this point that we have an admin with refreshed group memberships.
- Bugzilla->set_user($self->admin);
- foreach my $test (CUSTOM_SEARCH_TESTS) {
- my $custom_test = new Bugzilla::Test::Search::CustomTest($test, $self);
- $custom_test->run();
- }
- foreach my $test (SPECIAL_PARAM_TESTS) {
- my $operator_test =
- new Bugzilla::Test::Search::OperatorTest($test->{operator}, $self);
- my $field = Bugzilla::Field->check($test->{field});
- my $special_test = new Bugzilla::Test::Search::FieldTestNormal(
- $operator_test, $field, $test);
- $special_test->run();
- }
- foreach my $operator ($self->top_level_operators) {
- my $operator_test =
- new Bugzilla::Test::Search::OperatorTest($operator, $self);
- $operator_test->run();
- }
-
- # Rollbacks won't get rid of bugs_fulltext entries, so we do that ourselves.
- my @bug_ids = map { $_->id } $self->bugs;
- my $bug_id_string = join(',', @bug_ids);
- $dbh->do("DELETE FROM bugs_fulltext WHERE bug_id IN ($bug_id_string)");
- $dbh->bz_rollback_transaction();
- $self->repopulate_test_results();
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ # We want backtraces on any "die" message or any warning.
+ # Otherwise it's hard to trace errors inside of Bugzilla::Search from
+ # reading automated test run results.
+ local $SIG{__WARN__} = \&Carp::cluck;
+ local $SIG{__DIE__} = \&Carp::confess;
+
+ $dbh->bz_start_transaction();
+
+ # Some parameters need to be set in order for the tests to function
+ # properly.
+ my $everybody = $self->everybody;
+ my $params = Bugzilla->params;
+ local $params->{'useclassification'} = 1;
+ local $params->{'useqacontact'} = 1;
+ local $params->{'usetargetmilestone'} = 1;
+ local $params->{'mail_delivery_method'} = 'None';
+ local $params->{'timetrackinggroup'} = $everybody->name;
+ local $params->{'insidergroup'} = $everybody->name;
+
+ $self->_setup_bugs();
+
+ # Even though _setup_bugs set us as an admin, we want to be sure at
+ # this point that we have an admin with refreshed group memberships.
+ Bugzilla->set_user($self->admin);
+ foreach my $test (CUSTOM_SEARCH_TESTS) {
+ my $custom_test = new Bugzilla::Test::Search::CustomTest($test, $self);
+ $custom_test->run();
+ }
+ foreach my $test (SPECIAL_PARAM_TESTS) {
+ my $operator_test
+ = new Bugzilla::Test::Search::OperatorTest($test->{operator}, $self);
+ my $field = Bugzilla::Field->check($test->{field});
+ my $special_test
+ = new Bugzilla::Test::Search::FieldTestNormal($operator_test, $field, $test);
+ $special_test->run();
+ }
+ foreach my $operator ($self->top_level_operators) {
+ my $operator_test = new Bugzilla::Test::Search::OperatorTest($operator, $self);
+ $operator_test->run();
+ }
+
+ # Rollbacks won't get rid of bugs_fulltext entries, so we do that ourselves.
+ my @bug_ids = map { $_->id } $self->bugs;
+ my $bug_id_string = join(',', @bug_ids);
+ $dbh->do("DELETE FROM bugs_fulltext WHERE bug_id IN ($bug_id_string)");
+ $dbh->bz_rollback_transaction();
+ $self->repopulate_test_results();
}
# This makes a few changes to the bugs after they're created--changes
# that can only be done after all the bugs have been created.
sub _setup_bugs {
- my ($self) = @_;
- $self->_setup_dependencies();
- $self->_set_bug_id_fields();
- $self->_protect_bug_6();
+ my ($self) = @_;
+ $self->_setup_dependencies();
+ $self->_set_bug_id_fields();
+ $self->_protect_bug_6();
}
+
sub _setup_dependencies {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
-
- # Set up depedency relationships between the bugs.
- # Bug 1 + 6 depend on bug 2 and block bug 3.
- my $bug2 = $self->bug(2);
- my $bug3 = $self->bug(3);
- foreach my $number (1,6) {
- my $bug = $self->bug($number);
- my @original_delta = ($bug2->delta_ts, $bug3->delta_ts);
- Bugzilla->set_user($bug->reporter);
- $bug->set_dependencies([$bug2->id], [$bug3->id]);
- $bug->update($bug->delta_ts);
- # Setting dependencies changed the delta_ts on bug2 and bug3, so
- # re-set them back to what they were before. However, we leave
- # the correct update times in bugs_activity, so that the changed*
- # searches still work right.
- my $set_delta = $dbh->prepare(
- 'UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
- foreach my $row ([$original_delta[0], $bug2->id],
- [$original_delta[1], $bug3->id])
- {
- $set_delta->execute(@$row);
- }
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ # Set up depedency relationships between the bugs.
+ # Bug 1 + 6 depend on bug 2 and block bug 3.
+ my $bug2 = $self->bug(2);
+ my $bug3 = $self->bug(3);
+ foreach my $number (1, 6) {
+ my $bug = $self->bug($number);
+ my @original_delta = ($bug2->delta_ts, $bug3->delta_ts);
+ Bugzilla->set_user($bug->reporter);
+ $bug->set_dependencies([$bug2->id], [$bug3->id]);
+ $bug->update($bug->delta_ts);
+
+ # Setting dependencies changed the delta_ts on bug2 and bug3, so
+ # re-set them back to what they were before. However, we leave
+ # the correct update times in bugs_activity, so that the changed*
+ # searches still work right.
+ my $set_delta = $dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
+ foreach
+ my $row ([$original_delta[0], $bug2->id], [$original_delta[1], $bug3->id])
+ {
+ $set_delta->execute(@$row);
}
+ }
}
sub _set_bug_id_fields {
- my ($self) = @_;
- # BUG_ID fields couldn't be set before, because before we create bug 1,
- # we don't necessarily have any valid bug ids.)
- my @bug_id_fields = grep { $_->type == FIELD_TYPE_BUG_ID }
- $self->all_fields;
- foreach my $number (1..NUM_BUGS) {
- my $bug = $self->bug($number);
- $number = 1 if $number == 6;
- next if $number == 5;
- my $other_bug = $self->bug($number + 1);
- Bugzilla->set_user($bug->reporter);
- foreach my $field (@bug_id_fields) {
- $bug->set_custom_field($field, $other_bug->id);
- $bug->update($bug->delta_ts);
- }
+ my ($self) = @_;
+
+ # BUG_ID fields couldn't be set before, because before we create bug 1,
+ # we don't necessarily have any valid bug ids.)
+ my @bug_id_fields = grep { $_->type == FIELD_TYPE_BUG_ID } $self->all_fields;
+ foreach my $number (1 .. NUM_BUGS) {
+ my $bug = $self->bug($number);
+ $number = 1 if $number == 6;
+ next if $number == 5;
+ my $other_bug = $self->bug($number + 1);
+ Bugzilla->set_user($bug->reporter);
+ foreach my $field (@bug_id_fields) {
+ $bug->set_custom_field($field, $other_bug->id);
+ $bug->update($bug->delta_ts);
}
+ }
}
sub _protect_bug_6 {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
-
- Bugzilla->set_user($self->admin);
-
- # Put bug6 in the nobody group.
- my $nobody = $self->nobody;
- # We pull it newly from the DB to be sure it's safe to call update()
- # on.
- my $bug6 = new Bugzilla::Bug($self->bug(6)->id);
- $bug6->add_group($nobody);
- $bug6->update($bug6->delta_ts);
-
- # Remove the admin (and everybody else) from the $nobody group.
- $dbh->do('DELETE FROM group_group_map
- WHERE grantor_id = ? OR member_id = ?', undef,
- $nobody->id, $nobody->id);
+ my ($self) = @_;
+ my $dbh = Bugzilla->dbh;
+
+ Bugzilla->set_user($self->admin);
+
+ # Put bug6 in the nobody group.
+ my $nobody = $self->nobody;
+
+ # We pull it newly from the DB to be sure it's safe to call update()
+ # on.
+ my $bug6 = new Bugzilla::Bug($self->bug(6)->id);
+ $bug6->add_group($nobody);
+ $bug6->update($bug6->delta_ts);
+
+ # Remove the admin (and everybody else) from the $nobody group.
+ $dbh->do(
+ 'DELETE FROM group_group_map
+ WHERE grantor_id = ? OR member_id = ?', undef, $nobody->id,
+ $nobody->id
+ );
}
1;
diff --git a/xt/lib/Bugzilla/Test/Search/AndTest.pm b/xt/lib/Bugzilla/Test/Search/AndTest.pm
index f34ba1f3a..6132c0eb6 100644
--- a/xt/lib/Bugzilla/Test/Search/AndTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/AndTest.pm
@@ -22,13 +22,13 @@ use constant type => 'AND';
# 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;
+ 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;
+ my ($self, $number) = @_;
+ return all { $_->will_actually_contain_bug($number) } $self->field_tests;
}
##############################
@@ -36,17 +36,17 @@ sub _bug_will_actually_be_contained {
##############################
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;
+ 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
index 5d84ec6ff..84080cfe8 100644
--- a/xt/lib/Bugzilla/Test/Search/Constants.pm
+++ b/xt/lib/Bugzilla/Test/Search/Constants.pm
@@ -17,28 +17,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
@@ -63,6 +63,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;
@@ -74,40 +75,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
@@ -115,40 +113,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
@@ -156,9 +157,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
);
################
@@ -178,42 +179,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]},
);
@@ -238,110 +239,92 @@ 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 => {
- greaterthan => { GREATERTHAN_BROKEN },
- greaterthaneq => { GREATERTHAN_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] },
- },
+ '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] },
- },
+ # 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]},},
};
###################
@@ -350,135 +333,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]},},
};
#############
@@ -489,113 +427,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 => []},
);
#########
@@ -637,7 +579,7 @@ use constant CHANGED_OVERRIDE => (
# 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.
@@ -655,301 +597,330 @@ 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] },
- },
- },
- ],
- # XXX these need tests developed
- isempty => [],
- isnotempty => [],
+ 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.
@@ -958,59 +929,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 },
- isempty => { search => 1 },
- isnotempty => { search => 1 },
+ 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' }
+ {value => ';SEMICOLON_TEST'},
+ {value => '--COMMENT_TEST'},
+ {value => "'QUOTE_TEST"},
+ {value => "';QUOTE_SEMICOLON_TEST"},
+ {value => '/*STAR_COMMENT_TEST'}
);
#################
@@ -1018,185 +992,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 => '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 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 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 => '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 => '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 => '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 => '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 => '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 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 = 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) )',
+ 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 => '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>'},
+ ]
+ },
);
diff --git a/xt/lib/Bugzilla/Test/Search/CustomTest.pm b/xt/lib/Bugzilla/Test/Search/CustomTest.pm
index 132e5ac40..7455d4828 100644
--- a/xt/lib/Bugzilla/Test/Search/CustomTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/CustomTest.pm
@@ -24,7 +24,7 @@ use Storable qw(dclone);
sub new {
my ($class, $test, $search_test) = @_;
- bless { raw_test => dclone($test), search_test => $search_test }, $class;
+ bless {raw_test => dclone($test), search_test => $search_test}, $class;
}
#############
@@ -32,31 +32,33 @@ sub new {
#############
sub search_test { return $_[0]->{search_test} }
-sub name { return 'Custom: ' . $_[0]->test->{name} }
-sub test { return $_[0]->{raw_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" }
+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 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;
+ 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 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 }
#########################################
@@ -66,36 +68,35 @@ sub invalid_field_operator_combination { return undef }
# 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++;
+ 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;
+ 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;
+ 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} || [] }];
+ 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
index 5e86d92e2..2ccaab735 100644
--- a/xt/lib/Bugzilla/Test/Search/FieldTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/FieldTest.pm
@@ -26,10 +26,12 @@ use Test::Exception;
###############
sub new {
- my ($class, $operator_test, $field, $test) = @_;
- return bless { operator_test => $operator_test,
- field_object => $field,
- raw_test => $test }, $class;
+ my ($class, $operator_test, $field, $test) = @_;
+ return bless {
+ operator_test => $operator_test,
+ field_object => $field,
+ raw_test => $test
+ }, $class;
}
#############
@@ -40,144 +42,156 @@ 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};
+ 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(@_);
+ 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;
+ 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;
+ 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};
+ 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};
+ 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} };
+ 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} };
+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;
+ 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);
}
- return $self->{translated_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";
+ 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};
+ 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;
+ 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;
}
###################################################
@@ -186,112 +200,114 @@ sub bug_is_contained {
# 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 {};
+ 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 ($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;
+ 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;
+ 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 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);
+ # 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;
+ 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;
+ 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;
+ 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;
+ 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};
- }
+ 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;
+ }
+ return $or_broken;
}
#########################################
@@ -300,28 +316,28 @@ sub join_broken {
# 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 ($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,
+ );
- 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};
+ $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;
+ 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;
}
@@ -330,103 +346,107 @@ sub search_columns {
################
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;
+ 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 ($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;
- }
+ 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);
+ 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 ();
+ 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};
+ my ($self, $from, $field) = @_;
+ if (blessed($from)) {
+ return $from->$field;
+ }
+ return $from->{$field};
}
#####################
@@ -439,83 +459,85 @@ sub _get_item {
# 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;
+ 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;
+ 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);
+ 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);
}
#####################
@@ -523,95 +545,93 @@ sub _substr_value {
#####################
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();
- }
+ 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 ($self) = @_;
+ my $name = $self->name;
- my $search_broken = $self->search_known_broken;
-
- my $search = $self->_test_search_object_creation();
+ my $search_broken = $self->search_known_broken;
- 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);
- }
+ 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";
+ }
- $self->_test_content($results, $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;
+ 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;
+ 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) = @_;
+ 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);
- }
+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);
- }
+ 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
index 888e7eb13..101c09053 100644
--- a/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm
+++ b/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm
@@ -15,9 +15,9 @@ use parent qw(Bugzilla::Test::Search::FieldTest);
use Scalar::Util qw(blessed);
use constant CH_OPERATOR => {
- changedafter => 'chfieldfrom',
- changedbefore => 'chfieldto',
- changedto => 'chfieldvalue',
+ changedafter => 'chfieldfrom',
+ changedbefore => 'chfieldto',
+ changedto => 'chfieldvalue',
};
use constant EMAIL_FIELDS => qw(assigned_to qa_contact cc reporter commenter);
@@ -27,78 +27,79 @@ use constant EMAIL_FIELDS => qw(assigned_to qa_contact cc reporter commenter);
# 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(@_);
+ 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)";
+ 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(@_);
+ 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} || {} },
- };
+ 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 };
+ $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
index 90eaabc78..f34acc6bb 100644
--- a/xt/lib/Bugzilla/Test/Search/InjectionTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/InjectionTest.pm
@@ -18,60 +18,62 @@ 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 || {};
+ 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;
+ 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_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(@_);
+ 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
index 190b8567b..ea0ecc5b2 100644
--- a/xt/lib/Bugzilla/Test/Search/NotTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/NotTest.pm
@@ -20,9 +20,9 @@ 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;
+ my ($class, $field_test) = @_;
+ my $self = {%$field_test};
+ return bless $self, $class;
}
#############
@@ -30,32 +30,33 @@ sub new {
#############
sub name {
- my ($self) = @_;
- return "NOT(" . $self->SUPER::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;
+ 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');
+ 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;
+ 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
index 5ab502dfc..57d058ad7 100644
--- a/xt/lib/Bugzilla/Test/Search/OperatorTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/OperatorTest.pm
@@ -24,10 +24,10 @@ use Bugzilla::Test::Search::NotTest;
###############
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;
+ my ($invocant, $operator, $search_test) = @_;
+ $search_test ||= $invocant->search_test;
+ my $class = ref($invocant) || $invocant;
+ return bless {search_test => $search_test, operator => $operator}, $class;
}
#############
@@ -36,68 +36,69 @@ sub new {
# 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 } } }
+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();
- }
+ 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();
- }
+ 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();
+ 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
index 1b948f38d..ebb16089d 100644
--- a/xt/lib/Bugzilla/Test/Search/OrTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/OrTest.pm
@@ -20,36 +20,36 @@ use constant type => 'OR';
###############
sub new {
- my $class = shift;
- my $self = { field_tests => [@_] };
- return bless $self, $class;
+ my $class = shift;
+ my $self = {field_tests => [@_]};
+ return bless $self, $class;
}
#############
# Accessors #
#############
-sub field_tests { return @{ $_[0]->{field_tests} } }
+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);
+ 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;
+ 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);
+ my ($self) = @_;
+ my @values = map { $_->field . ' ' . $_->debug_value } $self->field_tests;
+ return join(' ' . $self->type . ' ', @values);
}
########################
@@ -57,61 +57,66 @@ sub debug_value {
########################
sub field_not_yet_implemented {
- my ($self) = @_;
- return $self->_join_messages('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');
+ my ($self) = @_;
+ return $self->_join_messages('invalid_field_operator_combination');
}
+
sub search_known_broken {
- my ($self) = @_;
- return $self->_join_messages('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);
+ 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;
+ 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);
+ 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;
}
- return undef;
+ die "broken test with no message" if !@messages;
+ return join(' AND ', @messages);
+ }
+ return undef;
}
##############################
@@ -119,23 +124,23 @@ sub contains_known_broken {
##############################
sub search_columns {
- my ($self) = @_;
- my @columns = map { @{ $_->search_columns } } $self->field_tests;
- return [uniq @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;
+ 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;