From 9b6ec1f545da1cc4088ddf9cc117747954e58e65 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Fri, 26 Feb 2016 17:57:55 +0000 Subject: Bug 1069799 - move the QA repository into the main repository r=LpSolit --- xt/lib/Bugzilla/Test/Search/FieldTest.pm | 617 ------------------------------- 1 file changed, 617 deletions(-) delete mode 100644 xt/lib/Bugzilla/Test/Search/FieldTest.pm (limited to 'xt/lib/Bugzilla/Test/Search/FieldTest.pm') diff --git a/xt/lib/Bugzilla/Test/Search/FieldTest.pm b/xt/lib/Bugzilla/Test/Search/FieldTest.pm deleted file mode 100644 index 5e86d92e2..000000000 --- a/xt/lib/Bugzilla/Test/Search/FieldTest.pm +++ /dev/null @@ -1,617 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# -# This Source Code Form is "Incompatible With Secondary Licenses", as -# defined by the Mozilla Public License, v. 2.0. - -# This module represents the tests that get run on a single -# operator/field combination for Bugzilla::Test::Search. -# This is where all the actual testing happens. -package Bugzilla::Test::Search::FieldTest; - -use strict; -use warnings; -use Bugzilla::Search; -use Bugzilla::Test::Search::Constants; -use Bugzilla::Util qw(trim); - -use Data::Dumper; -use Scalar::Util qw(blessed); -use Test::More; -use Test::Exception; - -############### -# Constructor # -############### - -sub new { - my ($class, $operator_test, $field, $test) = @_; - return bless { operator_test => $operator_test, - field_object => $field, - raw_test => $test }, $class; -} - -############# -# Accessors # -############# - -sub num_tests { return TESTS_PER_RUN } - -# The Bugzilla::Test::Search::OperatorTest that this is a child of. -sub operator_test { return $_[0]->{operator_test} } -# The Bugzilla::Field being tested. -sub field_object { return $_[0]->{field_object} } -# The name of the field being tested, which we need much more often -# than we need the object. -sub field { - my ($self) = @_; - $self->{field_name} ||= $self->field_object->name; - return $self->{field_name}; -} -# The Bugzilla::Test::Search object that this is a child of. -sub search_test { return $_[0]->operator_test->search_test } -# The operator being tested -sub operator { return $_[0]->operator_test->operator } -# The bugs currently being tested by Bugzilla::Test::Search. -sub bugs { return $_[0]->search_test->bugs } -sub bug { - my $self = shift; - return $self->search_test->bug(@_); -} -sub number { - my ($self, $id) = @_; - foreach my $number (1..NUM_BUGS) { - return $number if $self->search_test->bug($number)->id == $id; - } - return 0; -} - -# The name displayed for this test by Test::More. Used in test descriptions. -sub name { - my ($self) = @_; - my $field = $self->field; - my $operator = $self->operator; - my $value = $self->main_value; - - my $name = "$field-$operator-$value"; - if (my $extra_name = $self->test->{extra_name}) { - $name .= "-$extra_name"; - } - return $name; -} - -# The appropriate value from the TESTS constant for this test, taking -# into account overrides. -sub test { - my $self = shift; - return $self->{test} if $self->{test}; - - my %test = %{ $self->{raw_test} }; - - # We have field name overrides... - my $override = $test{override}->{$self->field}; - # And also field type overrides. - if (!$override) { - $override = $test{override}->{$self->field_object->type} || {}; - } - - foreach my $key (%$override) { - $test{$key} = $override->{$key}; - } - - $self->{test} = \%test; - return $self->{test}; -} - -# All the values for all the bugs for this field. -sub _field_values { - my ($self) = @_; - return $self->{field_values} if $self->{field_values}; - - my %field_values; - foreach my $number (1..NUM_BUGS) { - $field_values{$number} = $self->_field_values_for_bug($number); - } - $self->{field_values} = \%field_values; - return $self->{field_values}; -} -# The values for this field for the numbered bug. -sub bug_values { - my ($self, $number) = @_; - return @{ $self->_field_values->{$number} }; -} - -# The untranslated, non-overriden value--used in the name of the test -# and other places. -sub main_value { return $_[0]->{raw_test}->{value} } -# The untranslated test value, taking into account overrides. -sub test_value { return $_[0]->test->{value} }; -# The value translated appropriately for passing to Bugzilla::Search. -sub translated_value { - my $self = shift; - if (!exists $self->{translated_value}) { - my $value = $self->search_test->value_translation_cache($self); - if (!defined $value) { - $value = $self->_translate_value(); - $self->search_test->value_translation_cache($self, $value); - } - $self->{translated_value} = $value; - } - return $self->{translated_value}; -} -# Used in failure diagnostic messages. -sub debug_fail { - my ($self, $number, $results, $sql) = @_; - my @expected = @{ $self->test->{contains} }; - my @results = sort - map { $self->number($_) } - map { $_->[0] } - @$results; - return - " Value: '" . $self->translated_value . "'\n" . - "Expected: [" . join(',', @expected) . "]\n" . - " Results: [" . join(',', @results) . "]\n" . - trim($sql) . "\n"; -} - -# True for a bug if we ran the "transform" function on it and the -# result was equal to its first value. -sub transformed_value_was_equal { - my ($self, $number, $value) = @_; - if (@_ > 2) { - $self->{transformed_value_was_equal}->{$number} = $value; - $self->search_test->was_equal_cache($self, $number, $value); - } - my $cached = $self->search_test->was_equal_cache($self, $number); - return $cached if defined $cached; - return $self->{transformed_value_was_equal}->{$number}; -} - -# True if this test is supposed to contain the numbered bug. -sub bug_is_contained { - my ($self, $number) = @_; - my $contains = $self->test->{contains}; - if ($self->transformed_value_was_equal($number) - and !$self->test->{override}->{$self->field}->{contains}) - { - $contains = $self->test->{if_equal}->{contains}; - } - return grep($_ == $number, @$contains) ? 1 : 0; -} - -################################################### -# Accessors: Ways of doing SKIP and TODO on tests # -################################################### - -# The tests we know are broken for this operator/field combination. -sub _known_broken { - my ($self, $constant, $skip_pg_check) = @_; - - $constant ||= KNOWN_BROKEN; - my $field = $self->field; - my $type = $self->field_object->type; - my $operator = $self->operator; - my $value = $self->main_value; - my $value_name = "$operator-$value"; - if (my $extra_name = $self->test->{extra_name}) { - $value_name .= "-$extra_name"; - } - - my $value_broken = $constant->{$value_name}->{$field}; - $value_broken ||= $constant->{$value_name}->{$type}; - return $value_broken if $value_broken; - my $operator_broken = $constant->{$operator}->{$field}; - $operator_broken ||= $constant->{$operator}->{$type}; - return $operator_broken if $operator_broken; - return {}; -} - -# True if the "contains" search for the numbered bug is broken. -# That is, either the result is supposed to contain it and doesn't, -# or the result is not supposed to contain it and does. -sub contains_known_broken { - my ($self, $number) = @_; - my $field = $self->field; - my $operator = $self->operator; - - my $contains_broken = $self->_known_broken->{contains} || []; - if (grep($_ == $number, @$contains_broken)) { - return "$field $operator contains $number is known to be broken"; - } - return undef; -} - -# Used by subclasses. Checks both bug_is_contained and contains_known_broken -# to tell you whether or not the bug will *actually* be found by the test. -sub will_actually_contain_bug { - my ($self, $number) = @_; - my $is_contained = $self->bug_is_contained($number) ? 1 : 0; - my $is_broken = $self->contains_known_broken($number) ? 1 : 0; - - # If the test is supposed to contain the bug and *isn't* broken, - # then the test will contain the bug. - return 1 if ($is_contained and !$is_broken); - # If this test is *not* supposed to contain the bug, but that test is - # broken, then this test *will* contain the bug. - return 1 if (!$is_contained and $is_broken); - - return 0; -} - -# Returns a string if creating a Bugzilla::Search object throws an error, -# with this field/operator/value combination. -sub search_known_broken { - my ($self) = @_; - my $field = $self->field; - my $operator = $self->operator; - if ($self->_known_broken->{search}) { - return "Bugzilla::Search for $field $operator is known to be broken"; - } - return undef; -} - -# Returns a string if we haven't yet implemented the tests for this field, -# but we plan to in the future. -sub field_not_yet_implemented { - my ($self) = @_; - my $skip_this_field = grep { $_ eq $self->field } SKIP_FIELDS; - if ($skip_this_field) { - my $field = $self->field; - return "$field testing not yet implemented"; - } - return undef; -} - -# Returns a message if this field/operator combination can't ever be run. -# At no time in the future will this field/operator combination ever work. -sub invalid_field_operator_combination { - my ($self) = @_; - my $field = $self->field; - my $operator = $self->operator; - - if ($field eq 'content' && $operator !~ /matches/) { - return "content field does not support $operator"; - } - elsif ($operator =~ /matches/ && $field ne 'content') { - return "matches operator does not support fields other than content"; - } - return undef; -} - -# True if this field is broken in an OR combination. -sub join_broken { - my ($self, $or_broken_map) = @_; - my $or_broken = $or_broken_map->{$self->field . '-' . $self->operator}; - if (!$or_broken) { - # See if this is a comment field, and in that case, if there's - # a generic entry for all comment fields. - my $is_comment_field = COMMENT_FIELDS->{$self->field}; - if ($is_comment_field) { - $or_broken = $or_broken_map->{'longdescs.-' . $self->operator}; - } - } - return $or_broken; -} - -######################################### -# Accessors: Bugzilla::Search Arguments # -######################################### - -# The data that will get passed to Bugzilla::Search as its arguments. -sub search_params { - my ($self) = @_; - return $self->{search_params} if $self->{search_params}; - - my %params = ( - "field0-0-0" => $self->field, - "type0-0-0" => $self->operator, - "value0-0-0" => $self->translated_value, - ); - - $self->{search_params} = \%params; - return $self->{search_params}; -} - -sub search_columns { - my ($self) = @_; - my $field = $self->field; - my @search_fields = qw(bug_id); - if ($self->field_object->buglist) { - my $col_name = COLUMN_TRANSLATION->{$field} || $field; - push(@search_fields, $col_name); - } - return \@search_fields; -} - - -################ -# Field Values # -################ - -sub _field_values_for_bug { - my ($self, $number) = @_; - my $field = $self->field; - - my @values; - - if ($field =~ /^attach.+\.(.+)$/ ) { - my $attach_field = $1; - $attach_field = ATTACHMENT_FIELDS->{$attach_field} || $attach_field; - @values = $self->_values_for($number, 'attachments', $attach_field); - } - elsif (my $flag_field = FLAG_FIELDS->{$field}) { - @values = $self->_values_for($number, 'flags', $flag_field); - } - elsif (my $translation = COMMENT_FIELDS->{$field}) { - @values = $self->_values_for($number, 'comments', $translation); - # We want the last value to come first, so that single-value - # searches use the last comment. - @values = reverse @values; - } - elsif ($field eq 'longdescs.count') { - @values = scalar(@{ $self->bug($number)->comments }); - } - elsif ($field eq 'work_time') { - @values = $self->_values_for($number, 'actual_time'); - } - elsif ($field eq 'bug_group') { - @values = $self->_values_for($number, 'groups_in', 'name'); - } - elsif ($field eq 'keywords') { - @values = $self->_values_for($number, 'keyword_objects', 'name'); - } - elsif ($field eq 'content') { - @values = $self->_values_for($number, 'short_desc'); - } - elsif ($field eq 'see_also') { - @values = $self->_values_for($number, 'see_also', 'name'); - } - elsif ($field eq 'tag') { - @values = $self->_values_for($number, 'tags'); - } - # Bugzilla::Bug truncates creation_ts, but we need the full value - # from the database. This has no special value for changedfrom, - # because it never changes. - elsif ($field eq 'creation_ts') { - my $bug = $self->bug($number); - my $creation_ts = Bugzilla->dbh->selectrow_array( - 'SELECT creation_ts FROM bugs WHERE bug_id = ?', - undef, $bug->id); - @values = ($creation_ts); - } - else { - @values = $self->_values_for($number, $field); - } - - # We convert user objects to their login name, here, all in one - # block for simplicity. - if (grep { $_ eq $field } USER_FIELDS) { - # requestees.login_name is empty for most bugs (but checking - # blessed(undef) handles that. - # Values that come from %original_values aren't User objects. - @values = map { blessed($_) ? $_->login : $_ } @values; - @values = grep { defined $_ } @values; - } - - return \@values; -} - -sub _values_for { - my ($self, $number, $bug_field, $item_field) = @_; - - my $item; - if ($self->operator eq 'changedfrom') { - $item = $self->search_test->bug_create_value($number, $bug_field); - } - else { - my $bug = $self->bug($number); - $item = $bug->$bug_field; - } - - if ($item_field) { - if ($bug_field eq 'flags' and $item_field eq 'name') { - return (map { $_->name . $_->status } @$item); - } - return (map { $self->_get_item($_, $item_field) } @$item); - } - - return @$item if ref($item) eq 'ARRAY'; - return $item if defined $item; - return (); -} - -sub _get_item { - my ($self, $from, $field) = @_; - if (blessed($from)) { - return $from->$field; - } - return $from->{$field}; -} - -##################### -# Value Translation # -##################### - -# This function translates the "value" specified in TESTS into an actual -# search value to pass to Search.pm. This means that we get the value -# from the current bug (or, in the case of changedfrom, from %original_values) -# and then we insert it as required into the "value" from TESTS. (For example, -# <1> becomes the value for the field from bug 1.) -sub _translate_value { - my $self = shift; - my $value = $self->test_value; - foreach my $number (1..NUM_BUGS) { - $value = $self->_translate_value_for_bug($number, $value); - } - # Sanity check to make sure that none of the <> stuff was left in. - if ($value =~ /<\d/) { - die $self->name . ": value untranslated: $value\n"; - } - return $value; -} - -sub _translate_value_for_bug { - my ($self, $number, $value) = @_; - - my $bug = $self->bug($number); - - my $bug_id = $bug->id; - $value =~ s/<$number-id>/$bug_id/g; - my $bug_delta = $bug->delta_ts; - $value =~ s/<$number-delta>/$bug_delta/g; - my $reporter = $bug->reporter->login; - $value =~ s/<$number-reporter>/$reporter/g; - if ($value =~ /<$number-bug_group>/) { - my @bug_groups = map { $_->name } @{ $bug->groups_in }; - @bug_groups = grep { $_ =~ /^\d+-group-/ } @bug_groups; - my $group = $bug_groups[0]; - $value =~ s/<$number-bug_group>/$group/g; - } - - my @bug_values = $self->bug_values($number); - return $value if !@bug_values; - - if ($self->operator =~ /substr/) { - @bug_values = map { $self->_substr_value($_) } @bug_values; - } - - my $string_value = $bug_values[0]; - if ($self->operator =~ /word/) { - $string_value = join(' ', @bug_values); - } - if (my $func = $self->test->{transform}) { - my $transformed = $func->(@bug_values); - my $is_equal = $transformed eq $bug_values[0] ? 1 : 0; - $self->transformed_value_was_equal($number, $is_equal); - $string_value = $transformed; - } - - if ($self->test->{escape}) { - $string_value = quotemeta($string_value); - } - $value =~ s/<$number>/$string_value/g; - - return $value; -} - -sub _substr_value { - my ($self, $value) = @_; - my $field = $self->field; - my $type = $self->field_object->type; - my $substr_size = SUBSTR_SIZE; - if (exists FIELD_SUBSTR_SIZE->{$field}) { - $substr_size = FIELD_SUBSTR_SIZE->{$field}; - } - elsif (exists FIELD_SUBSTR_SIZE->{$type}) { - $substr_size = FIELD_SUBSTR_SIZE->{$type}; - } - if ($substr_size > 0) { - # The field name is included in every field value, and if it's - # long, it might take up the whole substring, and we don't want that. - if (!grep { $_ eq $field or $_ eq $type } SUBSTR_NO_FIELD_ADD) { - $substr_size += length($field); - } - my $string = substr($value, 0, $substr_size); - return $string; - } - return substr($value, $substr_size); -} - -##################### -# Main Test Methods # -##################### - -sub run { - my ($self) = @_; - - my $invalid_combination = $self->invalid_field_operator_combination; - my $field_not_implemented = $self->field_not_yet_implemented; - - SKIP: { - skip($invalid_combination, $self->num_tests) if $invalid_combination; - TODO: { - todo_skip ($field_not_implemented, $self->num_tests) if $field_not_implemented; - $self->do_tests(); - } - } -} - -sub do_tests { - my ($self) = @_; - my $name = $self->name; - - my $search_broken = $self->search_known_broken; - - my $search = $self->_test_search_object_creation(); - - my $sql; - TODO: { - local $TODO = $search_broken if $search_broken; - lives_ok { $sql = $search->_sql } "$name: generate SQL"; - } - - my $results; - SKIP: { - skip "Can't run SQL without any SQL", 1 if !defined $sql; - $results = $self->_test_sql($search); - } - - $self->_test_content($results, $sql); -} - -sub _test_search_object_creation { - my ($self) = @_; - my $name = $self->name; - my @args = (fields => $self->search_columns, params => $self->search_params); - my $search; - lives_ok { $search = new Bugzilla::Search(@args) } - "$name: create search object"; - return $search; -} - -sub _test_sql { - my ($self, $search) = @_; - my $name = $self->name; - my $results; - lives_ok { $results = $search->data } "$name: Run SQL Query" - or diag($search->_sql); - return $results; -} - -sub _test_content { - my ($self, $results, $sql) = @_; - - SKIP: { - skip "Without results we can't test them", NUM_BUGS if !$results; - foreach my $number (1..NUM_BUGS) { - $self->_test_content_for_bug($number, $results, $sql); - } - } -} - -sub _test_content_for_bug { - my ($self, $number, $results, $sql) = @_; - my $name = $self->name; - - my $contains_known_broken = $self->contains_known_broken($number); - - my %result_ids = map { $_->[0] => 1 } @$results; - my $bug_id = $self->bug($number)->id; - - TODO: { - local $TODO = $contains_known_broken if $contains_known_broken; - if ($self->bug_is_contained($number)) { - ok($result_ids{$bug_id}, - "$name: contains bug $number ($bug_id)") - or diag $self->debug_fail($number, $results, $sql); - } - else { - ok(!$result_ids{$bug_id}, - "$name: does not contain bug $number ($bug_id)") - or diag $self->debug_fail($number, $results, $sql); - } - } -} - -1; -- cgit v1.2.3-24-g4f1b