summaryrefslogtreecommitdiffstats
path: root/xt/lib/Bugzilla/Test/Search/FieldTest.pm
diff options
context:
space:
mode:
Diffstat (limited to 'xt/lib/Bugzilla/Test/Search/FieldTest.pm')
-rw-r--r--xt/lib/Bugzilla/Test/Search/FieldTest.pm806
1 files changed, 413 insertions, 393 deletions
diff --git a/xt/lib/Bugzilla/Test/Search/FieldTest.pm b/xt/lib/Bugzilla/Test/Search/FieldTest.pm
index 832c578cc..fc7b107c3 100644
--- a/xt/lib/Bugzilla/Test/Search/FieldTest.pm
+++ b/xt/lib/Bugzilla/Test/Search/FieldTest.pm
@@ -40,10 +40,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;
}
#############
@@ -54,144 +56,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 ($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 $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 $self = shift;
+ return $self->{test} if $self->{test};
- my %test = %{ $self->{raw_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} || {};
- }
+ # We have field name overrides...
+ my $override = $test{override}->{$self->field};
- foreach my $key (%$override) {
- $test{$key} = $override->{$key};
- }
+ # And also field type overrides.
+ if (!$override) {
+ $override = $test{override}->{$self->field_object->type} || {};
+ }
- $self->{test} = \%test;
- return $self->{test};
+ 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 ($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 %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;
}
###################################################
@@ -200,112 +214,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 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 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);
- return 0;
+ # If this test is *not* supposed to contain the bug, but that test is
+ # broken, then this test *will* contain the bug.
+ return 1 if (!$is_contained and $is_broken);
+
+ return 0;
}
# Returns a string if creating a Bugzilla::Search object throws an error,
# with this field/operator/value combination.
sub search_known_broken {
- my ($self) = @_;
- my $field = $self->field;
- my $operator = $self->operator;
- if ($self->_known_broken->{search}) {
- return "Bugzilla::Search for $field $operator is known to be broken";
- }
- return undef;
+ 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;
+ 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;
+ 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;
}
#########################################
@@ -314,28 +330,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;
}
@@ -344,103 +360,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};
}
#####################
@@ -453,83 +473,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);
}
#####################
@@ -537,95 +559,93 @@ sub _substr_value {
#####################
sub run {
- my ($self) = @_;
+ my ($self) = @_;
- my $invalid_combination = $self->invalid_field_operator_combination;
- my $field_not_implemented = $self->field_not_yet_implemented;
+ 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();
- }
+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_broken = $self->search_known_broken;
- my $search = $self->_test_search_object_creation();
+ my $search = $self->_test_search_object_creation();
- my $sql;
- TODO: {
- local $TODO = $search_broken if $search_broken;
- lives_ok { $sql = $search->_sql } "$name: generate SQL";
- }
+ my $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 $results;
+SKIP: {
+ skip "Can't run SQL without any SQL", 1 if !defined $sql;
+ $results = $self->_test_sql($search);
+ }
- $self->_test_content($results, $sql);
+ $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;