'Generic method to test the validity of search results.
@param form_type: This can either be search.simple_form or
search.advanced_form
@param results_expected: Are results expected?
@param fields: See the `fields` function.
For search.simple_form, an empty list [] can be pass. The field will be taken from s3resource.
@param row_count: Expected row count
For search.simple_form,
{"tablename":tablename, "key":key, "filters":[(field,value),...]}
can be pass to get the resource and eventually the DB row count.
Keyword arguments:
These let you specify the kinds of checks to perform on the resulting
datatable. Here are some of the options:
1. data - You can pass in your own function here that receives the data
from the results table as an argument. Return true if your check is
successful and false otherwise. This directly corresponds to the
\'dt_data\' function.
2. manual_check - You can pass in your own function here, and it\'ll
receive this instance as an argument. This can be used for all other
kinds of checks.
3. match_row - You can use this to match a series of values to a row in
the result data table. The first value must be the index of the row to
match against.
4. match_column - You can use this to match a series of values to a
column in the result data table. The first value must be the index of
the row to match against.'

def search(self, form_type, results_expected, fields, row_count, **kwargs):

    current.auth.override = True
    if (isinstance(row_count, dict) and (form_type == self.search.simple_form)):
        key = row_count['key']
        resource = current.s3db.resource(row_count['tablename'])
        simpleSearch = resource.search_method().simple[0]
        if (len(fields) == 0):
            fields = ({'name': simpleSearch[0], 'value': key},)
        searchFields = simpleSearch[1].field
        for i in xrange(len(searchFields)):
            if (i == 0):
                query = FS(searchFields[i]).like((('%' + key) + '%'))
            else:
                query |= FS(searchFields[i]).like((('%' + key) + '%'))
        filters = row_count.get('filters', None)
        if (filters is not None):
            for filter in filters:
                qfilter = (resource.table[filter[0]] == filter[1])
                resource.add_filter(qfilter)
        resource.add_filter(query)
        row_count = resource.count()
    browser = self.browser
    clear_button = browser.find_elements_by_xpath("//a[text()='Clear']")
    if clear_button[0].is_displayed():
        clear_button[0].click()
    else:
        clear_button[1].click()
    try:
        if (form_type == self.search.advanced_form):
            link = browser.find_element_by_xpath("//a[@class='action-lnk    advanced-lnk']")
        elif (form_type == self.search.simple_form):
            link = browser.find_element_by_xpath("//a[@class='action-lnk    simple-lnk']")
    except NoSuchElementException:
        link = None
    if (link and link.is_displayed()):
        link.click()
    time.sleep(1)
    self.fill_fields(fields)
    if (isinstance(row_count, dict) and (form_type == self.search.advanced_form)):
        resource = current.s3db.resource(row_count['tablename'])
        search_list = resource.search_method().advanced
        for search in search_list:
            widget = search[1]
            if isinstance(widget, S3SearchOptionsWidget):
                values = []
                elem_list = browser.find_elements_by_name(widget.attr._name)
                for elem in elem_list:
                    if elem.get_attribute('checked'):
                        values.append(int(s3_unicode(elem.get_attribute('value'))))
                if (len(values) > 0):
                    query = widget.query(resource, values)
                    resource.add_filter(query)
        filters = row_count.get('filters', None)
        if (filters is not None):
            for filter in filters:
                qfilter = (resource.table[filter[0]] == filter[1])
                resource.add_filter(qfilter)
        row_count = resource.count()
    browser.find_element_by_name(('simple_submit', 'advanced_submit')[form_type]).click()
    time.sleep(1)
    if results_expected:
        self.assertFalse((browser.find_element_by_id('table-container').text == 'No    Records    Found'), 'No    results    found,    when    results    expected.')
    else:
        return
    htmlRowCount = self.dt_row_cnt()[2]
    successMsg = (((('DB    row    count    (' + str(row_count)) + ')    matches    the    HTML    datatable    row    count    (') + str(htmlRowCount)) + ').')
    failMsg = (((('DB    row    count    (' + str(row_count)) + ')    does    not    match    the    HTML    datatable    row    count    (') + str(htmlRowCount)) + ').')
    self.assertTrue((row_count == htmlRowCount), failMsg)
    self.reporter(successMsg)
    if ('data' in kwargs.keys()):
        self.assertTrue(bool(kwargs['data'](self.dt_data())), 'Data    verification    failed.')
    if ('manual_check' in kwargs.keys()):
        self.assertTrue(bool(kwargs['manual_check'](self)), 'Manual    checks    failed.')
    if ('match_row' in kwargs.keys()):
        data = self.dt_data(row_list=kwargs['match_row'][0])
        kwargs['match_row'] = kwargs['match_row'][1:]
        for (a, b) in zip(kwargs['match_row'], data):
            self.assertTrue((a == b), 'Row    match    failed.')
    if ('match_column' in kwargs.keys()):
        column_index = kwargs['match_column'][0]
        kwargs['match_column'] = kwargs['match_column'][1:]
        shown_items = [dt_data_item(column=column_index, row=r) for r in xrange(1, (len(kwargs['match_column']) + 1))]
        for item in kwargs['match_column']:
            self.assertTrue((item in shown_items))
    return self.dt_data()
