Index: chrome/test/functional/autofill_dataset_generator.py |
=================================================================== |
--- chrome/test/functional/autofill_dataset_generator.py (revision 0) |
+++ chrome/test/functional/autofill_dataset_generator.py (revision 0) |
@@ -0,0 +1,305 @@ |
+#!/usr/bin/python |
+# Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Generates profile dictionaries for Autofill. |
+ |
+Used to test autofill.AutoFillTest.FormFillLatencyAfterSubmit. |
+Can be used as a stand alone script with -h to print out help text by running: |
+ python autofill_dataset_generator.py -h |
+""" |
+ |
+import codecs |
+import logging |
+from optparse import OptionParser |
+import os |
+import random |
+import re |
+import sys |
+ |
+ |
+class NullHandler(logging.Handler): |
+ def emit(self, record): |
+ pass |
+ |
+ |
+class DatasetGenerator(object): |
+ """Generates a dataset of dictionaries. |
+ |
+ The lists (such as address_construct, city_construct) define the way the |
+ corresponding field is generated. They accomplish this by specifying a |
+ list of function-args lists. |
+ """ |
+ address_construct = [ |
+ [ random.randint, 1, 10000], |
+ [ None, u'foobar'], |
+ [ random.choice, [ u'St', u'Ave', u'Ln', u'Ct', ]], |
+ [ random.choice, [ u'#1', u'#2', u'#3', ]], |
+ ] |
+ |
+ city_construct = [ |
+ [ random.choice, [ u'San Jose', u'San Francisco', u'Sacramento', |
+ u'Los Angeles', ]], |
+ ] |
+ |
+ state_construct = [ |
+ [ None, u'CA'] |
+ ] |
+ |
+ zip_construct = [ |
+ [ None, u'95110'] |
+ ] |
+ |
+ re_single_quote = re.compile('\'', re.UNICODE) |
+ logger = logging.getLogger(__name__) |
+ logger.addHandler(NullHandler()) |
+ log_handlers = {'StreamHandler': None} |
+ |
+ def __init__(self, output_filename=None, logging_level=None): |
+ """Constructs dataset generator object. |
+ |
+ Creates 'fields' data member which is a list of pair (two values) lists. |
+ These pairs are comprised of a field key e.g. u'NAME_FIRST' and a |
+ generator method e.g. self.GenerateNameFirst which will generate the value. |
+ If we want the value to always be the same e.g. u'John' we can use this |
+ instead of a method. We can even use None keyword which will give |
+ a value of u''. |
+ |
+ 'output_pattern' for one field would have been: "{u'NAME_FIRST': u'%s',}" |
+ which is ready to accept a value for the 'NAME_FIRST' field key once |
+ this value is generated. |
+ 'output_pattern' is used in 'GenerateNextDict()' to generate the next |
+ dict line. |
+ |
+ Args: |
+ output_filename: specified filename of generated dataset to be saved. |
+ Default value is None and no saving takes place. |
+ logging_level: set verbosity levels, default is None. |
+ """ |
+ if logging_level: |
+ if not self.log_handlers['StreamHandler']: |
+ console = logging.StreamHandler() |
+ console.setLevel(logging.INFO) |
+ self.log_handlers['StreamHandler'] = console |
+ self.logger.addHandler(console) |
+ self.logger.setLevel(logging_level) |
+ else: |
+ if self.log_handlers['StreamHandler']: |
+ self.logger.removeHandler(self._log_handlers['StreamHandler']) |
+ self.log_handlers['StreamHandler'] = None |
+ |
+ self.output_filename = output_filename |
+ |
+ self.dict_no = 0 |
+ self.fields = [ |
+ [u'NAME_FIRST', self.GenerateNameFirst], |
+ [u'NAME_MIDDLE', None], |
+ [u'NAME_LAST', None], |
+ [u'EMAIL_ADDRESS', self.GenerateEmail], |
+ [u'COMPANY_NAME', None], |
+ [u'ADDRESS_HOME_LINE1', self.GenerateAddress], |
+ [u'ADDRESS_HOME_LINE2', None], |
+ [u'ADDRESS_HOME_CITY', self.GenerateCity], |
+ [u'ADDRESS_HOME_STATE', self.GenerateState], |
+ [u'ADDRESS_HOME_ZIP', self.GenerateZip], |
+ [u'ADDRESS_HOME_COUNTRY', u'United States'], |
+ [u'PHONE_HOME_WHOLE_NUMBER', None], |
+ [u'PHONE_FAX_WHOLE_NUMBER', u'6501234555'], |
+ ] |
+ |
+ self.dict_length = len(self.fields) |
+ self.output_pattern = u'{' |
+ for key_and_method in self.fields: |
+ self.output_pattern += u'u"%s": u"%s", ' % (key_and_method[0], "%s") |
+ self.output_pattern = self.output_pattern[:-1] + '},' # Del last space. |
+ |
+ def _GenerateField(self, field_construct): |
+ """Generates each field in each dictionary. |
+ |
+ Args: |
+ field_construct: it is a list of lists. |
+ The first value (index 0) of each containing list is a function or None. |
+ The remaining values are the args. If function is None then arg is just |
+ returned. |
+ |
+ Example 1: zip_construct = [[ None, u'95110']]. There is one |
+ containing list only and function here is None and arg is u'95110'. |
+ This just returns u'95110'. |
+ |
+ Example 2: address_construct = [ [ random.randint, 1, 10000], |
+ [ None, u'foobar'] ] This has two containing lists and it will return |
+ the result of: |
+ random.randint(1, 10000) + ' ' + u'foobar' |
+ which could be u'7832 foobar' |
+ """ |
+ parts = [] |
+ for function_and_args in field_construct: |
+ function = function_and_args[0] |
+ args = function_and_args[1:] |
+ if not function: |
+ function = lambda x: x |
+ parts.append(u'%s' % function(*args)) |
+ return (' ').join(parts) |
+ |
+ def GenerateAddress(self): |
+ """Uses _GenerateField() and address_construct to gen a random address. |
+ |
+ Returns: |
+ A random address. |
+ """ |
+ return self._GenerateField(self.address_construct) |
+ |
+ def GenerateCity(self): |
+ """Uses _GenerateField() and city_construct to gen a random city. |
+ |
+ Returns: |
+ A random city. |
+ """ |
+ return self._GenerateField(self.city_construct) |
+ |
+ def GenerateState(self): |
+ """Uses _GenerateField() and state_construct to generate a state. |
+ |
+ Returns: |
+ A random state. |
+ """ |
+ return self._GenerateField(self.state_construct) |
+ |
+ def GenerateZip(self): |
+ """Uses _GenerateField() and zip_construct to generate a zip code. |
+ |
+ Returns: |
+ A random zip code. |
+ """ |
+ return self._GenerateField(self.zip_construct) |
+ |
+ def GenerateCountry(self): |
+ """Uses _GenerateField() and country_construct to generate a country. |
+ |
+ Returns: |
+ A random country. |
+ """ |
+ return self._GenerateField(self.country_construct) |
+ |
+ def GenerateNameFirst(self): |
+ """Generates a numerical first name. |
+ |
+ The name is the number of the current dict. |
+ i.e. u'1', u'2', u'3' |
+ |
+ Returns: |
+ A random first name. |
+ """ |
+ return u'%s' % self.dict_no |
+ |
+ def GenerateEmail(self): |
+ """Generates an email that corresponds to the first name. |
+ |
+ i.e. u'1@example.com', u'2@example.com', u'3@example.com' |
+ |
+ Returns: |
+ A random email address. |
+ """ |
+ return u'%s@example.com' % self.dict_no |
+ |
+ |
+ def GenerateNextDict(self): |
+ """Generates next dictionary of the dataset. |
+ |
+ Returns: |
+ The output dictionary. |
+ """ |
+ self.dict_no += 1 |
+ output_dict = {} |
+ for key, method_or_value in self.fields: |
+ if not method_or_value: |
+ output_dict[key] = '' |
+ elif type(method_or_value) in [str, unicode]: |
+ output_dict[key] = '%s' % method_or_value |
+ else: |
+ output_dict[key] = method_or_value() |
+ output_dict[key] = self.re_single_quote.sub( |
+ r'\'', output_dict[key]) # Escaping single quote: "'" -> '\'' |
+ return output_dict |
+ |
+ def GenerateDataset(self, num_of_dict_to_generate=10): |
+ """Generates a list of dictionaries. |
+ |
+ Args: |
+ num_of_dict_to_generate: The number of dictionaries to be generated. |
+ Default value is 10. |
+ |
+ Returns: |
+ The dictionary list. |
+ """ |
+ if self.output_filename: |
+ output_file = codecs.open( |
+ self.output_filename, mode='wb', encoding='utf-8-sig') |
+ else: |
+ output_file = None |
+ try: |
+ list_of_dict = [] |
+ if output_file: |
+ output_file.write('[') |
+ output_file.write(os.linesep) |
+ |
+ while self.dict_no < num_of_dict_to_generate: |
+ output_dict = self.GenerateNextDict() |
+ list_of_dict.append(output_dict) |
+ output_line = self.output_pattern % tuple( |
+ [output_dict[key_and_method[0]] for key_and_method in self.fields]) |
+ if output_file: |
+ output_file.write(output_line) |
+ output_file.write(os.linesep) |
+ self.logger.info( |
+ '%d: %s' % (self.dict_no, output_line.encode(sys.stdout.encoding, |
+ 'ignore'))) |
+ |
+ if output_file: |
+ output_file.write(']') |
+ output_file.write(os.linesep) |
+ self.logger.info('%d dictionaries generated SUCCESSFULLY!', self.dict_no) |
+ self.logger.info('--- FINISHED ---') |
+ return list_of_dict |
+ finally: |
+ if output_file: |
+ output_file.close() |
+ |
+def main(): |
+ # Command line options. |
+ parser = OptionParser() |
+ parser.add_option( |
+ '-o', '--output', dest='output_filename', default='', |
+ help='write output to FILE [optional]', metavar='FILE') |
+ parser.add_option( |
+ '-d', '--dict', type='int', dest='dict_no', metavar='DICT_NO', default=10, |
+ help='DICT_NO: number of dictionaries to be generated [default: %default]') |
+ parser.add_option( |
+ '-l', '--log_level', dest='log_level', default='debug', |
+ metavar='LOG_LEVEL', |
+ help='LOG_LEVEL: "debug", "info", "warning" or "error" [default: %default]') |
+ |
+ (options, args) = parser.parse_args() |
+ if args: |
+ parser.print_help() |
+ sys.exit(1) |
+ options.log_level = options.log_level.lower() |
+ if options.log_level not in ['debug', 'info', 'warning', 'error']: |
+ parser.error('Wrong log_level argument.') |
+ else: |
+ if options.log_level == 'debug': |
+ options.log_level = logging.DEBUG |
+ elif options.log_level == 'info': |
+ options.log_level = logging.INFO |
+ elif options.log_level == 'warning': |
+ options.log_level = logging.WARNING |
+ elif options.log_level == 'error': |
+ options.log_level = logging.ERROR |
+ |
+ gen = DatasetGenerator(options.output_filename, options.log_level) |
+ gen.GenerateDataset(options.dict_no) |
+ |
+ |
+if __name__ == '__main__': |
+ main() |