diff --git a/.nocover.yaml b/.nocover.yaml index 614510d..e557f4a 100644 --- a/.nocover.yaml +++ b/.nocover.yaml @@ -12,6 +12,7 @@ nocover_file_globs: - coala_quickstart/info_extractors/EditorconfigParsing.py - coala_quickstart/info_extractors/GemfileInfoExtractor.py - coala_quickstart/info_extractors/GruntfileInfoExtractor.py + - coala_quickstart/green_mode/green_mode_core.py nocover_regexes: # coala_quickstart.py diff --git a/coala_quickstart/coala_quickstart.py b/coala_quickstart/coala_quickstart.py index bd06428..44a1b5b 100644 --- a/coala_quickstart/coala_quickstart.py +++ b/coala_quickstart/coala_quickstart.py @@ -25,6 +25,10 @@ generate_settings, write_coafile) from coala_quickstart.generation.SettingsClass import ( collect_bear_settings) +from coala_quickstart.green_mode.green_mode_core import green_mode + +MAX_NUM_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE = 5 +MAX_NUM_OF_VALUES_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE = 5 def _get_arg_parser(): @@ -110,7 +114,12 @@ def main(): used_languages, printer, arg_parser, extracted_information) if args.green_mode: - collect_bear_settings(relevant_bears) + bear_settings_obj = collect_bear_settings(relevant_bears) + green_mode( + project_dir, ignore_globs, relevant_bears, bear_settings_obj, + MAX_NUM_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE, + MAX_NUM_OF_VALUES_OF_OPTIONAL_ARGS_ALLOWED_FOR_GREEN_MODE, + printer) print_relevant_bears(printer, relevant_bears) diff --git a/coala_quickstart/generation/Utilities.py b/coala_quickstart/generation/Utilities.py index 440e36e..6031c23 100644 --- a/coala_quickstart/generation/Utilities.py +++ b/coala_quickstart/generation/Utilities.py @@ -3,6 +3,7 @@ import os from collections import defaultdict import re +import yaml from coala_utils.Extensions import exts from coala_utils.string_processing import unescaped_search_for @@ -236,3 +237,125 @@ def peek(iterable): except StopIteration: return None return first, itertools.chain([first], iterable) + + +def contained_in(smaller, bigger): + """ + Takes in two SourceRange objects and checks whether + the first one lies inside the other one. + :param smaller: + The SourceRange object that needs to be checked whether + it is inside the other one. + :param bigger: + The SourceRange object that needs to be checked whether + it contains the other one. + :return: + True if smaller is inside the bigger else false. + """ + smaller_file = smaller.start.file + bigger_file = bigger.start.file + + smaller_start_line = smaller.start.line + smaller_start_column = smaller.start.column + smaller_end_line = smaller.end.line + smaller_end_column = smaller.end.column + + bigger_start_line = bigger.start.line + bigger_start_column = bigger.start.column + bigger_end_line = bigger.end.line + bigger_end_column = bigger.end.column + + if None in [smaller_start_line, smaller_start_column, + smaller_end_line, smaller_end_column, + bigger_start_line, bigger_start_column, + bigger_end_line, bigger_end_column]: + return False + + if not smaller_file == bigger_file: + return False + + if smaller_start_line < bigger_start_line: + return False + + if smaller_end_line > bigger_end_line: + return False + + if smaller_start_line > bigger_start_line and ( + smaller_end_line < bigger_end_line): + return True + + same_start_line = (smaller_start_line == bigger_start_line) + + same_end_line = (smaller_end_line == bigger_end_line) + + if same_start_line and same_end_line: + if smaller_start_column < bigger_start_column: + return False + if smaller_end_column > bigger_end_column: + return False + return True + + if same_start_line: + if smaller_start_column < bigger_start_column: + return False + return True + + assert same_end_line + if smaller_end_column > bigger_end_column: + return False + return True + + +def get_yaml_contents(project_data): + """ + Reads a YAML file and returns the data. + :param project_data: + The file path from which to read data. + :return: + The YAML data as python objects. + """ + with open(project_data, 'r') as stream: + return yaml.load(stream) + + +def dump_yaml_to_file(file, contents): + """ + Writes YAML data to a file. + :param file: + The file to write YAML data to. + :param contents: + The python objects to be written as YAML data. + """ + with open(file, 'w+') as outfile: + yaml.dump(contents, outfile, + default_flow_style=False) + + +def append_to_contents(contents, key, values, settings_key): + """ + Appends data to a dict, adding the received values + to the list of values at a given key or creating + the key if it does not exist. + :param contents: + The dict to append data to. + :param key: + The key needed to be appended to the dict. + :param values: + The list of values needed to be appended to the + values at a key in the dict. + :param settings_key: + The key to which data has to be appended to. + :return: + The dict with appended key and values. + """ + found = False + if settings_key not in contents: + contents[settings_key] = [] + for index, obj in enumerate(contents[settings_key]): + if isinstance(obj, dict) and key in obj.keys(): + found = True + contents[settings_key][index][key] += values + if not found: + contents[settings_key].append({key: values}) + + return contents diff --git a/coala_quickstart/green_mode/Setting.py b/coala_quickstart/green_mode/Setting.py new file mode 100644 index 0000000..6e75989 --- /dev/null +++ b/coala_quickstart/green_mode/Setting.py @@ -0,0 +1,36 @@ +settings_key = 'green_mode_infinite_value_settings' + + +def find_max_min_of_setting(setting, value, contents, operator): + """ + Generates min/max value of a setting where this + function is called upon for every value generated for + every file in the project (excluding ignored files). + :param setting: + The setting for which to find the min value of. + :param value: + The current value to be compared against the + supposedly min value stored in contents. + :param contents: + The python object to be written to 'PROJECT_DATA' + which contains the min value of the setting which was + encountered uptil now. + :param operator: + Either the less than or greater than operator. + :return: + The contents with the min value of the setting encountered + uptil now after comparing it with the current value recieved + by the function. + """ + found = False + for index, item in enumerate(contents[settings_key]): + if isinstance(item, dict) and setting in item: + found = True + position = index + if not found: + contents[settings_key].append({setting: value}) + return contents + current_val = contents[settings_key][position][setting] + if operator(value, current_val): + contents[settings_key][position][setting] = value + return contents diff --git a/coala_quickstart/green_mode/filename_operations.py b/coala_quickstart/green_mode/filename_operations.py new file mode 100644 index 0000000..6798570 --- /dev/null +++ b/coala_quickstart/green_mode/filename_operations.py @@ -0,0 +1,147 @@ +import os +from copy import deepcopy + +from coala_quickstart.generation.Utilities import ( + append_to_contents, + ) +from coala_quickstart.green_mode.green_mode import ( + settings_key, + ) + + +class Node: + def __init__(self, character, parent=None): + self.count = 1 + self.character = character + self.children = {} + self.parent = parent + + def insert(self, string, idx): + if idx >= len(string): + return + code = ord(string[idx]) # ASCII code + ch = string[idx] + if ch in self.children: + self.children[ch].count += 1 + else: + self.children[ch] = Node(string[idx], self) + self.children[ch].insert(string, idx + 1) + + +class Trie: + """ + Creates a Trie data structure for storing names of files. + """ + + def __init__(self): + self.root = Node('') + + def insert(self, string): + self.root.insert(string, 0) + + # Just a wrapper function. + def get_prefixes(self, min_length, min_files): + """ + Discovers prefix from the Trie. Prefix shorter than the + min_length or matching against files lesser than the + min_files are not stored. Returns the prefixes in sorted + order. + """ + self.prefixes = {} + self._discover_prefixes(self.root, [], min_length, 0, min_files) + return sorted(self.prefixes.items(), key=lambda x: (x[1], x[0]), + reverse=True) + + def _discover_prefixes(self, node, prefix, min_length, len, min_files): + """ + Performs a DFA search on the trie. Discovers the prefixes in the trie + and stores them in the self.prefixes dictionary. + """ + if node.count < min_files and node.character != '': + return + if len >= min_length: + current_prefix = ''.join(prefix) + node.character + to_delete = [] + for i in self.prefixes: + if i in current_prefix: + to_delete.append(i) + for i in to_delete: + self.prefixes.pop(i) + self.prefixes[''.join(prefix) + node.character] = node.count + orig_prefix = deepcopy(prefix) + for ch, ch_node in node.children.items(): + prefix.append(node.character) + if (not ch_node.count < node.count) or orig_prefix == []: + self._discover_prefixes(ch_node, prefix, min_length, len + 1, + min_files) + prefix.pop() + + +def get_files_list(contents): + """ + Generates a list which contains only files from + the entire project from the directory and file + structure written to '.project_data.yaml'. + :param contents: + The python object containing the file and + directory structure written to '.project_data.yaml'. + :return: + The list of all the files in the project. + """ + file_names_list = [] + for item in contents: + if not isinstance(item, dict): + file_names_list.append(item) + else: + file_names_list += get_files_list( + item[next(iter(item))]) + return file_names_list + + +def check_filename_prefix_postfix(contents, min_length_of_prefix=6, + min_files_for_prefix=5): + """ + Checks whether the project has some files with filenames + having certain prefix or postfix. + :param contents: + The python object containing the file and + directory structure written to '.project_data.yaml'. + :param min_length_of_prefix: + The minimum length of prefix for it green_mode to + consider as a valid prefix. + :param min_files_for_prefix: + The minimum amount of files a prefix to match against + for green_mode to consider it as a valid prefix. + :return: + Update contents value with the results found out + from the file/directory structure in .project_data.yaml. + """ + file_names_list = get_files_list(contents['dir_structure']) + file_names_list = [os.path.splitext(os.path.basename(x))[ + 0] for x in file_names_list] + file_names_list_reverse = [os.path.splitext( + x)[0][::-1] for x in file_names_list] + trie = Trie() + for file in file_names_list: + trie.insert(file) + prefixes = trie.get_prefixes(min_length_of_prefix, min_files_for_prefix) + trie_reverse = Trie() + for file in file_names_list_reverse: + trie_reverse.insert(file) + suffixes = trie_reverse.get_prefixes( + min_length_of_prefix, min_files_for_prefix) + if len(suffixes) == 0: + suffixes = [('', 0)] + if len(prefixes) == 0: + prefixes = [('', 0)] + prefix_list, suffix_list = [], [] + for prefix, freq in prefixes: + prefix_list.append(prefix) + for suffix, freq in suffixes: + suffix_list.append(suffix[::-1]) + contents = append_to_contents(contents, 'filename_prefix', prefix_list, + settings_key) + contents = append_to_contents(contents, 'filename_suffix', suffix_list, + settings_key) + + return contents diff --git a/coala_quickstart/green_mode/green_mode.py b/coala_quickstart/green_mode/green_mode.py new file mode 100644 index 0000000..34990e6 --- /dev/null +++ b/coala_quickstart/green_mode/green_mode.py @@ -0,0 +1,427 @@ +import fnmatch +import itertools +import operator +import os +from copy import deepcopy +from pathlib import Path + +from coala_quickstart.generation.Utilities import ( + contained_in, + get_yaml_contents, + peek, + split_by_language, + ) +from coala_quickstart.generation.SettingsClass import ( + SettingTypes, + ) +from coala_quickstart.green_mode.Setting import ( + find_max_min_of_setting, + ) +from coala_quickstart.green_mode.QuickstartBear import ( + QuickstartBear, + ) +from coalib.bears.GlobalBear import GlobalBear +from coalib.processes.Processing import ( + get_file_dict, + yield_ignore_ranges, + ) +from coalib.settings.Section import Section + + +settings_key = 'green_mode_infinite_value_settings' + + +def initialize_project_data(dir, ignore_globs): + """ + Generates the values for the key 'dir_structure' + for PROJECT_DATA which is directories as + dicts with key name as dir names and value as + list of files or nested dict of dirs. + :param dir: + The directory for which to add the directory structure + and files. + :param ignore_globs: + The globs of files to ignore from writing to the + 'PROJECT_DATA'. + :return: + The python object that was written as YAML data + to PROJECT_DATA. + """ + files_dirs = os.listdir(dir) + # files_dirs holds names of both files and dirs. + dir_name = dir[dir.rfind(os.sep)+1:] + final_data = [] + + for i in files_dirs: + to_continue = False + for glob in ignore_globs: + if fnmatch.fnmatch(dir+i, glob): + to_continue = True + if to_continue is True: + continue + if os.path.isfile(dir+i): + final_data.append(i) + else: + look_into_dir = dir+i+os.sep + data = initialize_project_data(look_into_dir, + ignore_globs) + final_data.append({i: data}) + return final_data + + +def generate_complete_filename_list(contents, project_dir): + """ + Generates only a list of files with complete file + paths from the 'dir_structure' key of PROJECT_DATA. + :param contents: + The python object which contains the already parsed + directories and files. + :param project_dir: + The current directory from which to generate the list + of files and directories within itself. + :return: + List of files or nested lists of directories and the + structures within it to be appended to the contents + from where the function is called. + """ + prefix = project_dir + os.sep + file_names_list = [] + for item in contents: + if not isinstance(item, dict): + file_names_list.append(prefix + item) + else: + file_names_list += generate_complete_filename_list( + item[next(iter(item))], prefix+next(iter(item))) + return file_names_list + + +def run_quickstartbear(contents, project_dir): + """ + Runs the QuickstartBear which pareses the file_dict + to get the exact value of some settings which can attain + any infinite amount of values. + :param contents: + The python object written to 'PROJECT_DATA' which + contains the directory structure and values of some + settings which can attain an infinite set of values. + :param project_dir: + The project directory from which to get the files for the + QuickstartBear to run. + :return: + - An updated contents value after guessing values of certain + settings. + - Collection of SourceRange objects indicating the parts of + code to ignore. + - The complete file dict contains file names as keys and file + contents as values to those keys. + - The complete file name list from the project directory and sub + directories. + """ + section = Section('green_mode') + quickstartbear_obj = QuickstartBear(section, None) + + complete_filename_list = generate_complete_filename_list( + contents['dir_structure'], project_dir) + complete_file_dict = get_file_dict(complete_filename_list, + allow_raw_files=True) + ignore_ranges = list(yield_ignore_ranges(complete_file_dict)) + find_max = ['max_lines_per_file', 'max_line_length'] + find_min = ['min_lines_per_file'] + for key in complete_file_dict: + return_val = quickstartbear_obj.execute( + filename=key, file=complete_file_dict[key]) + return_val = return_val[0] + # eg. return_val = {'setting_name': value, ...} + if return_val is not None: + for setting in find_max: + contents = find_max_min_of_setting( + setting, return_val[setting], contents, + operator.gt) + + for setting in find_min: + contents = find_max_min_of_setting( + setting, return_val[setting], contents, + operator.lt) + + bear_settings = get_yaml_contents(str( + Path(__file__).parent / 'bear_settings.yaml'))['type2'] + full_dict = {} + + for small_dict in bear_settings.values(): + full_dict.update(small_dict) + + resort_to_default_settings = deepcopy(find_max) + resort_to_default_settings += find_min + + for setting_name in resort_to_default_settings: + default_val = full_dict[setting_name] + insert_index = -1 + for index, dict_ in enumerate(contents[settings_key]): + if setting_name in dict_: + current_val = dict_[setting_name] + insert_index = index + break + if 'current_val' in locals() and current_val < default_val: + contents[settings_key][insert_index][setting_name] = default_val + + return (contents, ignore_ranges, complete_file_dict, + complete_filename_list) + + +def get_setting_type(setting, bear, dir=None): + """ + Retrieves the type of setting according to cEP0022.md + and seperates the other settings from generation/SettingsClass + into type2, type3, type4 or unguessable at the moment based on + the data in bear_settings.yaml. + :param setting: + The setting name. + :param bear: + The bear class to which the setting belongs. + :param dir: + The directory where to look for `bear_settings.yaml`, defaults + to the `green_mode` directory. + :return: + - The type of setting according to bear_settings.yaml. + - The list of acceptable values in case of type3 setting + or the value guessed by the QuickstartBear which fits + the project or the default value in case of unguessable + settings. + """ + __location__ = os.path.realpath( + os.path.join(os.getcwd(), os.path.dirname(__file__))) if ( + dir is None) else dir + bear_settings = get_yaml_contents(os.path.join( + __location__, 'bear_settings.yaml')) + for type_setting in bear_settings: + for bear_names in bear_settings[type_setting]: + if bear_names in str(bear): + if setting in bear_settings[type_setting][bear_names]: + return (type_setting, + bear_settings[type_setting][bear_names][setting]) + + +def get_kwargs(settings, bear, contents, dir=None): + """ + Generates the keyword arguments to be provided to the run / + create_arguments / generate_config methods of the bears except + the keys: file and filename . + :param settings: + SettingsClass.BearSettings.optional_settings object or + SettingsClass.BearSettings.non_optional_settings object. + :param bear: + The bear class. + :param contents: + The python object containing the file and + directory structure written to 'PROJECT_DATA' and + some value of settings detected by QuickstartBear. + :param dir: + The directory where to look for `bear_settings.yaml`. + :return: + The keyword arguments required for the running of the bear + except the keys: file and filename. + """ + bool_options = [True, False] + kwargs = {} + for setting in settings.settings_bool: + kwargs[setting] = bool_options + for setting in settings.settings_others: + ret_val = get_setting_type(setting, bear, dir) + if ret_val is not None: + type_setting, values = ret_val + else: + type_setting, values = None, None + if type_setting == 'type2': + for items in contents[settings_key]: + for setting_name in items: + if setting_name == setting: + # FIXME: will fail if a type2 setting accepts list + # as an input. + kwargs[setting_name] = [items[setting_name]] if ( + not type(items[setting_name]) is list) else ( + items[setting_name]) + if type_setting == 'type3': + kwargs[setting] = values + + return kwargs + + +def check_bear_results(ret_val, ignore_ranges): + if len(ret_val) == 0: + return True + elif len(ignore_ranges) == 0: + return False + # Check whether all the results lie in an ignore_ranges object + for result in ret_val: + for ignores in ignore_ranges: + for range_object in result.affected_code: + if not contained_in(range_object, ignores[1]): + return False + return True + + +def local_bear_test(bear, file_dict, file_names, lang, kwargs, + ignore_ranges): + lang_files = split_by_language(file_names) + lang_files = {k.lower(): v for k, v in lang_files.items()} + + import multiprocessing as mp + pool = mp.Pool(processes=mp.cpu_count()-1) + + file_results = [] + + for file in lang_files[lang.lower()]: + kwargs['filename'] = [file] + kwargs['file'] = [file_dict[file]] + + results = [] + values = [] + + for vals in itertools.product(*kwargs.values()): + print_val = dict(zip(kwargs, vals)) + print_val.pop('file', None) + values.append(vals) + section = Section('test-section-local-bear') + bear_obj = bear(section, None) + ret_val = bear_obj.run(**dict(zip(kwargs, vals))) + ret_val = list(ret_val) + # FIXME: Multiprocessing not working on windows. + if os.name == 'nt': # pragma posix: no cover + results.append(check_bear_results(ret_val, ignore_ranges)) + else: # pragma nt: no cover + results.append(pool.apply(check_bear_results, + args=(ret_val, ignore_ranges))) + + for index, result in enumerate(results): + if result is True: + # A set of bear setting values is found to be green + # for a particular file + arguments = dict(zip(kwargs, values[index])) + arguments.pop('file') + file_results.append(arguments) + + return {bear: file_results} + + +def global_bear_test(bear, file_dict, kwargs, ignore_ranges): + import multiprocessing as mp + pool = mp.Pool(processes=mp.cpu_count()-1) + + results = [] + values = [] + file_results = [] + + for vals in itertools.product(*kwargs.values()): + values.append(vals) + section = Section('test-section-global-bear') + bear_obj = bear(section=section, message_queue=None, + file_dict=file_dict) + bear_obj.file_dict = file_dict + ret_val = bear_obj.run(**dict(zip(kwargs, vals))) + ret_val = list(ret_val) + if os.name == 'nt': # pragma posix: no cover + results.append(check_bear_results(ret_val, ignore_ranges)) + else: # pragma nt: no cover + results.append(pool.apply(check_bear_results, + args=(ret_val, ignore_ranges))) + + for index, result in enumerate(results): + if result is True: + # A set of bear setting values is found to be green for this bear + arguments = dict(zip(kwargs, values[index])) + file_results.append(arguments) + + return {bear: file_results} + + +def run_test_on_each_bear(bear, file_dict, file_names, lang, kwargs, + ignore_ranges, type_of_setting, printer=None): + if type_of_setting == 'non-op': + printer.print('Finding suitable values to necessary ' + 'settings for ' + bear.__name__ + + ' based on your project ...', + color='green') + else: + printer.print('Finding suitable values to all settings ' + 'for ' + bear.__name__ + + ' based on your project ...', + color='yellow' + ) + if issubclass(bear, GlobalBear): + file_results = global_bear_test(bear, file_dict, kwargs, + ignore_ranges) + else: + file_results = local_bear_test( + bear, file_dict, file_names, lang, kwargs, ignore_ranges) + return file_results + + +def bear_test_fun(bears, bear_settings_obj, file_dict, ignore_ranges, + contents, file_names, op_args_limit, value_to_op_args_limit, + printer=None): + """ + Tests the bears with the generated file dict and list of files + along with the values recieved for each and every type of setting + and checks whether they yield a result or not. A setting value + is said to be 'green' if no results are produced by the bear. The + bears are tested agains all possible combination of settings. + :param bear: + The bears from Constants/GREEN_MODE_COMPATIBLE_BEAR_LIST along + with Constants/IMPORTANT_BEAR_LIST. + :param bear_settings_obj: + The object of SettingsClass/BearSettings which stores the metadata + about whether a setting takes a boolean value or any other value. + :param file_dict: + A dict of file names as keys and file contents as values to those + keys. + :param ignore_ranges: + Collection of SourceRange objects. + :param contents: + The python object to be written to 'PROJECT_DATA' which + contains the file and directory structure of the project and values + of some settings that can take an infinite set of values guessed + by the QuickstartBear. + :param file_names: + The list of names of all the files in the project. + :param op_args_limit: + The maximum number of optional bear arguments allowed for guessing. + :param value_to_op_args_limit: + The maximum number of values to run the bear again and again for + a optioanl setting. + :return: + Two Result data structures, one when the bears are run only with + non-optional settings and the other including the optional settings. + The data structure consists of a dict with bear name as key and + a list of arguments for which a particular file was green with those + arguments. The file name can be deduced from the arguments itself. + The file contents have been chopped off from the arguments. + """ + final_non_op_results = [] + final_unified_results = [] + for lang in bears: + for bear in bears[lang]: + for settings in bear_settings_obj: + if settings.bear == bear: + # first get non optional settings + non_op_set = settings.non_optional_settings + op_set = settings.optional_settings + non_op_kwargs = get_kwargs(non_op_set, bear, contents) + op_kwargs = get_kwargs(op_set, bear, contents) + non_op_file_results = run_test_on_each_bear( + bear, file_dict, file_names, lang, non_op_kwargs, + ignore_ranges, 'non-op', printer) + if len(op_kwargs) < op_args_limit and not( + True in [len(value) > value_to_op_args_limit + for key, value in op_kwargs.items()]): + unified_kwargs = dict(non_op_kwargs) + unified_kwargs.update(op_kwargs) + unified_file_results = run_test_on_each_bear( + bear, file_dict, file_names, lang, + unified_kwargs, ignore_ranges, 'unified', + printer) + else: + unified_file_results = None + final_non_op_results.append(non_op_file_results) + final_unified_results.append(unified_file_results) + + return final_non_op_results, final_unified_results diff --git a/coala_quickstart/green_mode/green_mode_core.py b/coala_quickstart/green_mode/green_mode_core.py new file mode 100644 index 0000000..ec91433 --- /dev/null +++ b/coala_quickstart/green_mode/green_mode_core.py @@ -0,0 +1,86 @@ +import os + +from coala_quickstart.generation.Utilities import ( + get_yaml_contents, + dump_yaml_to_file, + ) +from coala_quickstart.green_mode.green_mode import ( + bear_test_fun, + initialize_project_data, + run_quickstartbear, + ) +from coala_quickstart.green_mode.filename_operations import ( + check_filename_prefix_postfix, + ) + +PROJECT_DATA = '.project_data.yaml' + + +def green_mode(project_dir: str, ignore_globs, bears, bear_settings_obj, + op_args_limit, value_to_op_args_limit, printer=None): + """ + Runs the green mode of coala-quickstart. + + Generates '.project_data.yaml' which contains the files and directory + structure of the project, runs the QuickstartBear which guesses some values + of settings the can take an infinite set of values by parsing the + file_dict and appends to `.project_data.yaml`. Runs some further linting + options based on file names etc. Calls the methods which test out whether + a setting value is green for a bear i.e. does not point out any error in + the code base and further generates sections and writes the green config + file for the project. + :param project_dir: + The project directory. + :param ignore_globs: + The globs of the files to ignore from the linting process. + :param bears: + The bears from Constants.GREEN_MODE_COMPATIBLE_BEAR_LIST along + with Constants.IMPORTANT_BEAR_LIST. + :param bear_settings_obj: + The object of SettingsClass/BearSettings which stores the metadata + about whether a setting takes a boolean value or any other value. + :param op_args_limit: + The maximum number of optional bear arguments allowed for guessing. + :param value_to_op_args_limit: + The maximum number of values to run the bear again and again for + a optional setting. + """ + from coala_quickstart.green_mode.filename_operations import ( + check_filename_prefix_postfix) + ignore_globs.append(os.join(project_dir, '.git', '**')) + project_data = project_dir + os.sep + PROJECT_DATA + + # Currently as a temporary measure, recreating the file at each run from + # scratch, as there is no mechanism created uptil now to reuse this data. + if os.path.isfile(project_data): + os.remove(project_data) + + if not os.path.isfile(project_data): + new_data = initialize_project_data(project_dir + os.sep, ignore_globs) + data_to_dump = {'dir_structure': new_data} + dump_yaml_to_file(project_data, data_to_dump) + + # Operations before the running of QuickstartBear are done over here. + # Eg. do operations on filenames over here. + project_data_contents = get_yaml_contents(project_data) + project_data_contents = check_filename_prefix_postfix( + project_data_contents) + + # Run QuickstartBear + (project_data_contents, ignore_ranges, file_dict, + file_names) = run_quickstartbear( + project_data_contents, project_dir) + + final_non_op_results, final_unified_results = bear_test_fun( + bears, bear_settings_obj, file_dict, + ignore_ranges, project_data_contents, file_names, + op_args_limit, value_to_op_args_limit, printer) + + # Call to create `.coafile` goes over here. + + # Final Dump. + dump_yaml_to_file(project_data, project_data_contents) + + # Delete .project_data.yaml for now as there is currently no mechanism + # added to reuse this data. + os.remove(project_data) diff --git a/setup.cfg b/setup.cfg index aa2ae49..4ee23a6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -60,6 +60,7 @@ omit = coala_quickstart/info_extractors/EditorconfigParsing.py coala_quickstart/info_extractors/GemfileInfoExtractor.py coala_quickstart/info_extractors/GruntfileInfoExtractor.py + coala_quickstart/green_mode/green_mode_core.py [coverage:report] fail_under = 100 diff --git a/tests/generation/UtilitiesTest.py b/tests/generation/UtilitiesTest.py index 8f4944d..9ba896e 100644 --- a/tests/generation/UtilitiesTest.py +++ b/tests/generation/UtilitiesTest.py @@ -6,9 +6,12 @@ from tests.test_bears.AllKindsOfSettingsDependentBear import ( AllKindsOfSettingsDependentBear) from coala_quickstart.generation.Utilities import ( + contained_in, get_default_args, get_all_args, search_for_orig, concatenate, peek, get_language_from_hashbang) +from coalib.results.SourcePosition import SourcePosition +from coalib.results.SourceRange import SourceRange def foo(): @@ -117,3 +120,106 @@ def give_empty_gen(): self.assertEqual(ret_val, None) self.assertEqual(ret_val_1, None) + + +class TestContainedIn(unittest.TestCase): + + def test_contained_in_1(self): + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=5, column=1) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=5, column=2) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=1, column=4) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + def test_contained_in_2(self): + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=5, column=1) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=1, column=9) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=1, column=6) + end = SourcePosition('a.py', line=4, column=2) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + start = SourcePosition('b.py', line=1, column=5) + end = SourcePosition('b.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + def test_contained_in_3(self): + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=5, column=1) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=2, column=5) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + def test_contained_in_4(self): + start = SourcePosition('a.py', line=3, column=5) + end = SourcePosition('a.py', line=5, column=1) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=1, column=5) + end = SourcePosition('a.py', line=6, column=1) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=3, column=5) + end = SourcePosition('a.py', line=6, column=1) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + def test_contained_in_5(self): + start = SourcePosition('a.py', line=3, column=5) + end = SourcePosition('a.py', line=5, column=1) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=2, column=5) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertTrue(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=3, column=8) + end = SourcePosition('a.py', line=7, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + def test_contained_in_6(self): + start = SourcePosition('a.py', line=3, column=5) + end = SourcePosition('a.py', line=5, column=7) + smaller = SourceRange(start, end) + + start = SourcePosition('a.py', line=3, column=5) + end = SourcePosition('a.py', line=5, column=6) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=2, column=8) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) + + start = SourcePosition('a.py', line=2, column=None) + end = SourcePosition('a.py', line=5, column=1) + bigger = SourceRange(start, end) + self.assertFalse(contained_in(smaller, bigger)) diff --git a/tests/green_mode/bear_settings.yaml b/tests/green_mode/bear_settings.yaml new file mode 100644 index 0000000..9221c06 --- /dev/null +++ b/tests/green_mode/bear_settings.yaml @@ -0,0 +1,9 @@ +typeX: + GummyBear: + key: '' +type2: + AllKindsOfSettingsBaseBear: + max_line_lengths: 1000 +type3: + AllKindsOfSettingsBaseBear: + no_line: [1, 2] diff --git a/tests/green_mode/example_.project_data.yaml b/tests/green_mode/example_.project_data.yaml new file mode 100644 index 0000000..5da1988 --- /dev/null +++ b/tests/green_mode/example_.project_data.yaml @@ -0,0 +1,11 @@ +dir_structure: + - .coafile + - example_file_1 + - example_folder_1: + - example_file_2 + - example_nested_folder_1: + - example_file_3 + - example_nested_folder_2: + - example_file_4 + - example_file_5 + - example_file_6 diff --git a/tests/green_mode/filename_operationsTest.py b/tests/green_mode/filename_operationsTest.py new file mode 100644 index 0000000..39e13f2 --- /dev/null +++ b/tests/green_mode/filename_operationsTest.py @@ -0,0 +1,153 @@ +import unittest +import yaml +from copy import deepcopy +from pathlib import Path + +from coala_quickstart.generation.Utilities import ( + append_to_contents, + ) +from coala_quickstart.green_mode.filename_operations import ( + check_filename_prefix_postfix, + get_files_list, + ) +from coala_quickstart.green_mode.green_mode import ( + settings_key, + ) + + +class TestFilenameOperations(unittest.TestCase): + + def test_get_files_list(self): + file_path = Path(__file__).parent / 'example_.project_data.yaml' + with file_path.open() as stream: + contents = yaml.load(stream) + files_list = get_files_list(contents['dir_structure']) + test_files_list = ['.coafile', 'example_file_1', + 'example_file_2', 'example_file_3', + 'example_file_4', 'example_file_5', + 'example_file_6'] + self.assertEqual(files_list, test_files_list) + + def test_check_filename_prefix_postfix(self): + # Files having a common prefix but no suffix. + file_path = Path(__file__).parent / 'example_.project_data.yaml' + with file_path.open() as stream: + contents = yaml.load(stream) + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 3) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + ['example_file_'], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Works well when min files and min length of prefix are sufficiently + # low. + contents = {'dir_structure': ['py_some_name.xyz', 'py_some_other.c', + 'py_yet_another_file.yaml']} + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 2, 2) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + ['py_'], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Works when min length of prefix and min files is exactly equal + # to the paramters passed. + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 3) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + ['py_'], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Doesn't work when min length of prefix exceeds the prefix value. + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 4, 3) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + [''], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Doesn't work when min files exceed the files for a given prefix. + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 4) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + [''], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Files having a prefix and a suffix + contents = {'dir_structure': ['py_some_name.xyz', + 'py_some_other_name.c', + 'py_yet_another_name.yaml']} + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 3) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + ['py_'], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + ['_name'], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Both prefix and suffix don't work if the number of files exceed. + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 4) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + [''], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + [''], + settings_key) + self.assertEqual(test_contents, ret_val_contents) + + # Files having 2 prefix and 1 suffix. + contents = {'dir_structure': ['some_file.xyz', + 'another_one.c', + 'my_aweesome_file.yaml', + 'some_made_up_thing', + 'READEME.md', + 'some_other_file', + 'some_random_string', + 'another_file_just_for_prefix', + 'another_random_string']} + ret_val_contents = check_filename_prefix_postfix(deepcopy(contents), + 3, 3) + test_contents = deepcopy(append_to_contents(deepcopy(contents), + 'filename_prefix', + ['some_', 'another_'], + settings_key)) + test_contents = append_to_contents(deepcopy(test_contents), + 'filename_suffix', + ['ing'], + settings_key) + self.assertEqual(test_contents, ret_val_contents) diff --git a/tests/green_mode/green_modeTest.py b/tests/green_mode/green_modeTest.py new file mode 100644 index 0000000..b8b7597 --- /dev/null +++ b/tests/green_mode/green_modeTest.py @@ -0,0 +1,360 @@ +import operator +import os +import unittest +import yaml +from copy import deepcopy +from pathlib import Path + +from coala_quickstart.generation.SettingsClass import ( + collect_bear_settings, + ) +from coala_quickstart.green_mode.Setting import ( + find_max_min_of_setting, + ) +from coala_quickstart.green_mode.green_mode import ( + bear_test_fun, + check_bear_results, + generate_complete_filename_list, + get_kwargs, + get_setting_type, + global_bear_test, + initialize_project_data, + local_bear_test, + run_quickstartbear, + ) +from coala_quickstart.generation.Utilities import ( + append_to_contents, + dump_yaml_to_file, + get_yaml_contents, + ) +from coala_quickstart.green_mode.QuickstartBear import ( + QuickstartBear) +from coalib.results.Result import Result +from coalib.results.SourceRange import ( + SourcePosition, + SourceRange, + ) +from tests.test_bears.AllKindsOfSettingsDependentBear import ( + AllKindsOfSettingsBaseBear, + ) +from tests.test_bears.TestGlobalBear import TestGlobalBear +from tests.test_bears.TestLocalBear import TestLocalBear + +settings_key = 'green_mode_infinite_value_settings' + + +class Test_green_mode(unittest.TestCase): + + def test_get_yaml_contents(self): + project_data = 'example_.project_data.yaml' + full_path = str(Path(__file__).parent / project_data) + yaml_contents = get_yaml_contents(full_path) + test_yaml_contents = { + 'dir_structure': ['.coafile', + 'example_file_1', + {'example_folder_1': ['example_file_2', + {'example_nested_folder_1': + ['example_file_3']}, + {'example_nested_folder_2': + ['example_file_4']}, + 'example_file_5']}, + 'example_file_6']} + self.assertEqual(yaml_contents, test_yaml_contents) + + def test_append_to_contents_1(self): + ret_contents = append_to_contents({}, 'key', [1, 2], settings_key) + self.assertEqual(ret_contents, {settings_key: [{'key': [1, 2]}]}) + + def test_append_to_contents_2(self): + ret_contents = append_to_contents({settings_key: []}, 'key', [1, 2], + settings_key) + self.assertEqual(ret_contents, {settings_key: [{'key': [1, 2]}]}) + + def test_append_to_contents_3(self): + ret_contents = append_to_contents({settings_key: [{'key': [3]}]}, + 'key', [1, 2], settings_key) + self.assertEqual(ret_contents, {settings_key: [{'key': [3, 1, 2]}]}) + + def test_append_to_contents_4(self): + ret_contents = append_to_contents({settings_key: + [{'key': [3]}, + {'some_other_key': [True]}, + 'some_other_entry_in_list']}, + 'key', [1, 2], settings_key) + self.assertEqual(ret_contents, {settings_key: + [{'key': [3, 1, 2]}, + {'some_other_key': [True]}, + 'some_other_entry_in_list']}) + + def test_dump_yaml_to_file(self): + file_path = str(Path(__file__).parent.parent.parent / 'output.yanl') + dump_yaml_to_file(file_path, ['GSoC 2018']) + file_path = Path(file_path) + with file_path.open() as stream: + test_contents = yaml.load(stream) + self.assertEqual(test_contents, ['GSoC 2018']) + os.remove(str(file_path)) + + def test_initialize_project_data(self): + dir_path = str(Path(__file__).parent) + os.sep + contents = initialize_project_data(dir_path, []) + pycache_index = -1 + for index, content in enumerate(contents): + if isinstance(content, dict): + if '__pycache__' in content.keys(): + pycache_index = index + break + if not pycache_index == -1: + del contents[pycache_index] + list_indices = [] + for index, content in enumerate(contents): + if content[-4:] == 'orig': + list_indices.append(index) + for i in range(0, len(list_indices)): + del contents[list_indices[i]] + for j in range(i + 1, len(list_indices)): + list_indices[j] = list_indices[j] - 1 + self.assertIn( + ['QuickstartBearTest.py', 'example_.project_data.yaml', + 'green_modeTest.py', 'filename_operationsTest.py'], + contents) + + def test_initialize_project_data(self): + dir_path = str(Path(__file__).parent) + os.sep + ignore_globs = ['*pycache*', '**.pyc', '**.orig'] + final_data = initialize_project_data(dir_path, ignore_globs) + test_final_data = ['QuickstartBearTest.py', + 'example_.project_data.yaml', + 'green_modeTest.py', + 'filename_operationsTest.py', + 'bear_settings.yaml', + {'test_dir': ['test_file.py']}] + self.assertCountEqual(final_data, test_final_data) + + def test_generate_complete_filename_list(self): + dir_path = str(Path(__file__).parent) + os.sep + ignore_globs = ['*pycache*', '**.pyc', '**.orig'] + data = initialize_project_data(dir_path, ignore_globs) + final_data = generate_complete_filename_list(data, dir_path[:-1]) + prefix = dir_path + test_final_data = ['QuickstartBearTest.py', + 'example_.project_data.yaml', + 'bear_settings.yaml', + 'green_modeTest.py', + 'filename_operationsTest.py', + 'test_dir' + os.sep + 'test_file.py'] + test_final_data = [prefix + x for x in test_final_data] + self.assertCountEqual(final_data, test_final_data) + + def test_find_max_min_of_setting_1(self): + final_contents = find_max_min_of_setting('key', 1, {settings_key: []}, + operator.gt) + test_contents = {settings_key: [{'key': 1}]} + self.assertEqual(final_contents, test_contents) + + def test_find_max_min_of_setting_2(self): + final_contents = find_max_min_of_setting( + 'key', 1, {settings_key: [{'key': 0}]}, operator.gt) + test_contents = {settings_key: [{'key': 1}]} + self.assertEqual(final_contents, test_contents) + + def test_find_max_min_of_setting_3(self): + final_contents = find_max_min_of_setting( + 'key', 1, {settings_key: [{'key': 2}]}, operator.gt) + test_contents = {settings_key: [{'key': 2}]} + self.assertEqual(final_contents, test_contents) + + def test_find_max_min_of_setting_4(self): + final_contents = find_max_min_of_setting('key', 1, {settings_key: []}, + operator.lt) + test_contents = {settings_key: [{'key': 1}]} + self.assertEqual(final_contents, test_contents) + + def test_find_max_min_of_setting_5(self): + final_contents = find_max_min_of_setting( + 'key', 1, {settings_key: [{'key': 0}]}, operator.lt) + test_contents = {settings_key: [{'key': 0}]} + self.assertEqual(final_contents, test_contents) + + def test_find_max_min_of_setting_6(self): + final_contents = find_max_min_of_setting( + 'key', 1, {settings_key: [{'key': 2}]}, operator.lt) + test_contents = {settings_key: [{'key': 1}]} + self.assertEqual(final_contents, test_contents) + + def test_run_quickstartbear(self): + dir_path = str(Path(__file__).parent) + os.sep + ignore_globs = ['*pycache*', '**.pyc', '**.orig'] + contents = initialize_project_data(dir_path, ignore_globs) + contents = {'dir_structure': contents, settings_key: []} + settings_key_values = [{'max_lines_per_file': 1000}, # default value + {'max_line_length': 80}, + {'min_lines_per_file': 5}] + test_contents = deepcopy(contents) + test_contents[settings_key] = settings_key_values + (final_contents, ignore_ranges, complete_file_dict, + complete_filename_list) = run_quickstartbear(contents, dir_path) + ignore_file_name = dir_path + 'test_dir' + os.sep + 'test_file.py' + start = SourcePosition(ignore_file_name, line=3, column=1) + stop = SourcePosition(ignore_file_name, line=4, column=20) + test_ignore_ranges = SourceRange(start, stop) + self.assertEqual(test_contents, final_contents) + self.assertEqual(ignore_ranges, [([], test_ignore_ranges)]) + + def test_run_quickstartbear_with_file_None(self): + # Mocking the method + QuickstartBear.execute = lambda *args, **kwargs: [None] + dir_path = str(Path(__file__).parent) + os.sep + contents = initialize_project_data(dir_path, []) + contents = {'dir_structure': contents, settings_key: []} + test_contents = deepcopy(contents) + (final_contents, ignore_ranges, complete_file_dict, + complete_filename_list) = run_quickstartbear(contents, dir_path) + self.assertEqual(test_contents, final_contents) + + def test_get_setting_type(self): + __location__ = os.path.realpath( + os.path.join(os.getcwd(), os.path.dirname(__file__))) + type_setting, val = get_setting_type( + 'key', 'GummyBear', __location__) + self.assertEqual(type_setting, 'typeX') + self.assertEqual(val, '') + + def test_get_kwargs_1(self): + relevant_bears = {'test': + {AllKindsOfSettingsBaseBear, }} + __location__ = os.path.realpath( + os.path.join(os.getcwd(), os.path.dirname(__file__))) + dir_path = str(Path(__file__).parent) + os.sep + ignore_globs = ['*pycache*', '**.pyc', '**.orig'] + bear_settings_obj = collect_bear_settings(relevant_bears) + non_optional_settings = bear_settings_obj[0].non_optional_settings + bear_settings_obj[0].optional_settings + contents = initialize_project_data(dir_path, ignore_globs) + contents = {'dir_structure': contents, + settings_key: [{'some_rubbish_setting': 'some_rubbish', + 'max_line_lengths': 60}]} + kwargs = get_kwargs(non_optional_settings, + [AllKindsOfSettingsBaseBear], + contents, __location__) + test_kwargs = {'use_bear': [True, False], + 'max_line_lengths': [60], + 'no_line': [1, 2]} + self.assertEqual(kwargs, test_kwargs) + + def test_get_kwargs_2(self): + relevant_bears = {'test': + {AllKindsOfSettingsBaseBear, }} + __location__ = os.path.realpath( + os.path.join(os.getcwd(), os.path.dirname(__file__))) + dir_path = str(Path(__file__).parent) + os.sep + ignore_globs = ['*pycache*', '**.pyc', '**.orig'] + bear_settings_obj = collect_bear_settings(relevant_bears) + bear_settings_obj[0].non_optional_settings + optional_settings = bear_settings_obj[0].optional_settings + contents = initialize_project_data(dir_path, ignore_globs) + contents = {'dir_structure': contents, + settings_key: [{'some_rubbish_setting': 'some_rubbish', + 'max_line_lengths': 60}]} + kwargs = get_kwargs(optional_settings, + [AllKindsOfSettingsBaseBear], + contents, __location__) + test_kwargs = {'use_space': [True, False], + 'use_tab': [True, False]} + self.assertEqual(kwargs, test_kwargs) + + def test_check_bear_results_1(self): + self.assertEqual(True, check_bear_results([], [])) + self.assertEqual(False, check_bear_results(['a'], [])) + + def test_check_bear_results_2(self): + start = SourcePosition('a.py', line=368, column=4) + end = SourcePosition('a.py', line=442, column=2) + range_object = SourceRange(start, end) + results = [Result(affected_code=[range_object], + message='green_mode', origin=QuickstartBear)] + + start = SourcePosition('a.py', line=268, column=4) + end = SourcePosition('a.py', line=542, column=2) + ignore_object = SourceRange(start, end) + ignore_ranges = [('+', ignore_object)] + self.assertTrue(check_bear_results(results, ignore_ranges)) + + def test_check_bear_results_3(self): + start = SourcePosition('a.py', line=368, column=4) + end = SourcePosition('a.py', line=442, column=2) + range_object = SourceRange(start, end) + results = [Result(affected_code=[range_object], + message='green_mode', origin=QuickstartBear)] + + start = SourcePosition('a.py', line=468, column=4) + end = SourcePosition('a.py', line=478, column=2) + ignore_object = SourceRange(start, end) + ignore_ranges = [('+=', ignore_object)] + self.assertFalse(check_bear_results(results, ignore_ranges)) + + def test_bear_test_fun_1(self): + from pyprint.ConsolePrinter import ConsolePrinter + printer = ConsolePrinter() + bears = {'Python': [TestLocalBear, TestGlobalBear]} + relevant_bears = {'test': + {TestLocalBear, TestGlobalBear, }} + bear_settings_obj = collect_bear_settings(relevant_bears) + file_dict = {'A.py': {'a\n', 'b\n'}, 'C.py': {'c\n', 'd\n'}} + dir_path = str(Path(__file__).parent) + os.sep + contents = initialize_project_data(dir_path, []) + file_names = ['A.py', 'C.py'] + non_op_results, unified_results = bear_test_fun( + bears, bear_settings_obj, file_dict, [], contents, + file_names, 5, 5, printer) + test_non_op_results = [{TestLocalBear: + [{'filename': 'A.py'}, + {'filename': 'C.py'}]}, + {TestGlobalBear: [{}]}] + test_unified_results = [{TestLocalBear: + [{'filename': 'A.py', + 'yield_results': False}, + {'filename': 'C.py', + 'yield_results': False}]}, + {TestGlobalBear: [{'yield_results': False}]}] + self.assertCountEqual(non_op_results[1][TestGlobalBear], + test_non_op_results[1][TestGlobalBear]) + self.assertCountEqual(unified_results[1][TestGlobalBear], + test_unified_results[1][TestGlobalBear]) + self.assertCountEqual(non_op_results[0][TestLocalBear], + test_non_op_results[0][TestLocalBear]) + self.assertCountEqual(unified_results[0][TestLocalBear], + test_unified_results[0][TestLocalBear]) + + def test_bear_test_fun_2(self): + from pyprint.ConsolePrinter import ConsolePrinter + printer = ConsolePrinter() + bears = {'Python': [TestLocalBear, TestGlobalBear]} + relevant_bears = {'test': + {TestLocalBear, TestGlobalBear, }} + bear_settings_obj = collect_bear_settings(relevant_bears) + file_dict = {'A.py': {'a\n', 'b\n'}, 'C.py': {'c\n', 'd\n'}} + dir_path = str(Path(__file__).parent) + os.sep + contents = initialize_project_data(dir_path, []) + file_names = ['A.py', 'C.py'] + non_op_results, unified_results = bear_test_fun( + bears, bear_settings_obj, file_dict, [], contents, + file_names, 1, 1, printer) + test_non_op_results = [{TestLocalBear: + [{'filename': 'A.py'}, + {'filename': 'C.py'}]}, + {TestGlobalBear: [{}]}] + test_unified_results = [{TestLocalBear: + [{'filename': 'A.py', + 'yield_results': False}, + {'filename': 'C.py', + 'yield_results': False}]}, + {TestGlobalBear: [{'yield_results': False}]}] + self.assertCountEqual(non_op_results[1][TestGlobalBear], + test_non_op_results[1][TestGlobalBear]) + self.assertCountEqual(non_op_results[0][TestLocalBear], + test_non_op_results[0][TestLocalBear]) + self.assertCountEqual(unified_results, [None, None]) + + def test_green_mode(self): + pass diff --git a/tests/green_mode/test_dir/test_file.py b/tests/green_mode/test_dir/test_file.py new file mode 100644 index 0000000..c967af4 --- /dev/null +++ b/tests/green_mode/test_dir/test_file.py @@ -0,0 +1,5 @@ +def func(): + pass +# ignore all +def ignore_func(): + pass diff --git a/tests/test_bears/TestGlobalBear.py b/tests/test_bears/TestGlobalBear.py new file mode 100644 index 0000000..11b8b80 --- /dev/null +++ b/tests/test_bears/TestGlobalBear.py @@ -0,0 +1,10 @@ +from coalib.bears.GlobalBear import GlobalBear + + +class TestGlobalBear(GlobalBear): + CAN_FIX = {} + LANGUAGES = {} + + def run(self, yield_results=False): + if yield_results: + yield 1 diff --git a/tests/test_bears/TestLocalBear.py b/tests/test_bears/TestLocalBear.py new file mode 100644 index 0000000..ecac597 --- /dev/null +++ b/tests/test_bears/TestLocalBear.py @@ -0,0 +1,10 @@ +from coalib.bears.LocalBear import LocalBear + + +class TestLocalBear(LocalBear): + CAN_FIX = {} + LANGUAGES = {} + + def run(self, filename, file, yield_results=False): + if yield_results: + yield 1