def test_basic(self): function = f.basic code = ['def {}(a, b):'.format(function.__name__), ' return b'] r = Rules(a=True, b=True, output=True) r.add(b=True, output=True) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_identity_explicit(self): """ Identity will yield same result even though False and True inputs are explicit specified. """ code = ['def {}(a):'.format(f.identity.__name__), ' return a'] r = Rules(a=True, output=True) r.add(a=False, output=False) solution = r.solve(f.identity) self.assertEqual(solution.implementation, code)
def test_code_generation_with_if(self): """ Test with outputs different from boolean. """ r = Rules(a=True, b=True, output=1) solution = r.solve(f.non_boolean_and, self) code = [ 'def ' + f.non_boolean_and.__name__ + '(a, b):', '', ' if a and b:', ' return 1', '', ' return False' ] self.assertEqual(solution.implementation, code)
def test_simple_constant_output(self): """ When the result output of the QM algorithm is an empty expression, that means that regardless of the input the output is constant. """ function = f.simple_constant_output code = ['def {}(a):'.format(function.__name__), ' return True'] r = Rules(a=True, output=True) r.add(a=False, output=True) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_function_outputs(self): """ When output is a function. """ function = f.output_function_obj out1 = f.fun8 code = [ 'def ' + function.__name__ + '(a, b):', '', ' if not a and b:', ' return ' + c.print_object(out1), '', ' return False' ] r = Rules(a=False, b=True, output=out1) # non-boolean output solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_basic_if(self): """test basic if statement""" function = f.basic_if ouput = 'le' code = [ 'def {}(a, b):'.format(function.__name__), '', ' if b:', " return \"{}\"".format(ouput), '', ' return False' ] r = Rules(a=True, b=True, output=ouput) r.add(b=True, output=ouput) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_mix_output_boolean(self): """ When ifs and pure boolean expression mix. """ function = f.mix_output out = 'a' code = [ 'def ' + function.__name__ + '(a, b):', '', ' if not a and b:', ' return ' + c.print_object(out), ' return a and b' ] r = Rules(a=False, b=True, output=out) # non-boolean output r.add(a=True, b=True) # boolean output solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_internal_code_arguments(self): """ Do logic with pieces of code that evaluate to boolean. """ function = f.with_internal_code_arg code = [ 'def ' + function.__name__ + '(a):', '', ' if isinstance(a, str):', ' return 2', '', ' return False' ] r = Rules(any_non_input_name=s.Code(code_str='isinstance(a, str)'), output=2) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_calling_another_function_no_args(self): """ Invoke function with NO arguments. """ function = f.another_call out = f.no_args code = [ 'def {}(a, b):'.format(function.__name__), '', ' if not a and b:', ' return {}()'.format(out.__name__), '', ' return False' ] r = Rules(a=False, b=True, output=out, output_args={}) # non-boolean output solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_calling_nested_functions(self): """ call nested functions. """ function = f.nested_call out_obj = s.Output(f.f, {'a': s.Output(f.g, {'a': s.Code(code_str='a')})}) code = [ 'def ' + function.__name__ + '(a):', '', ' if not a:', ' return ' + f.f.__name__ + '(' + f.g.__name__ + '(a))', '', ' return False' ] r = Rules(a=False, output=out_obj) solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_recursive_function(self): """ Will do recursion, extremely cool!!! """ function = f.recursive not_a = 'not a' args = {'a': s.Code(code_str=not_a)} out = s.Output(function, args) code = [ 'def {}(a):'.format(function.__name__), '', ' if {}:'.format(not_a), ' return 0', '', ' return {0}({1})'.format(function.__name__, not_a) ] r = Rules(a=False, output=0, default=out) solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_boolean_and_quasi_boolean_mix_true_values(self): """ Tests whether changing inputs for True and 1 outputs affect the final result. BY DEFAULT IF 1 AND TRUE are present will choose 1 as output. Test with both a boolean and quasi-boolean output. In python True == 1. Therefore output=1 is the same as output=True. """ code = [ 'def mix_true_values(a, b):', '', ' if a and not b or not a and b:', ' return 1', '', ' return False' ] r = Rules(a=True, b=False, output=1) # non-boolean output r.add(a=False, b=True, output=True) # boolean condition solution = r.solve(f.mix_true_values, self) self.assertEqual(solution.implementation, code)
def test_function_solve_with_no_unittest(self): """ Same as test_basic_if() test but with no unittest provided. """ function = f.basic_if ouput = 'le' code = [ 'def {}(a, b):'.format(function.__name__), '', ' if b:', " return \"{}\"".format(ouput), '', ' return False' ] r = Rules(a=True, b=True, output=ouput) r.add(b=True, output=ouput) solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_non_collision(self): """ Testing bigger stuff. Multiple ifs with multiple boolean variables """ r = Rules(a=True, b=True, c=True, output=0) # leave d out r.add(a=False, b=True, d=True, output=1) # leave c out r.add(a=True, c=False, d=True, output=2) # leave b out r.add(b=True, c=False, d=False, output=3) # leave a out r.solve(f.non_collision, self)
def test_calling_another_function_with_args(self): """ Invoke function with arguments. """ function = f.another_call2 args = {'a': s.Code(code_str='a'), 'b': s.Code(code_str='b')} out_f = f.another_call code = [ 'def {}(a, b):'.format(function.__name__), '', ' if not a and b:', ' return {}(a, b)'.format(out_f.__name__), '', ' return False' ] r = Rules(a=False, b=True, output=out_f, output_args=args) # non-boolean output solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_recursive_iteration(self): """ Will do recursive iteration, extremely cool!!! """ function = f.recursive_iteration array_len_0 = 'len(array) == 0' array_1 = 'array[1:]' args = {'array': s.Code(code_str=array_1)} out = s.Output(function, args) code = [ 'def {}(array):'.format(function.__name__), '', ' if {}:'.format(array_len_0), ' return 0', '', ' return {0}({1})'.format(function.__name__, array_1) ] r = Rules(r1=s.Code(code_str=array_len_0), output=0, default=out) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def multiple_value_test(self, out1, out2, function): """ Testing multiple output types. :param out1: anything :param out2: anything :param function: object """ code = [ 'def ' + function.__name__ + '(a, b):', '', ' if not a and b:', ' return ' + c.print_object(out1), '', ' if a and not b:', ' return ' + c.print_object(out2), '', ' return False' ] r = Rules(a=False, b=True, output=out1) # non-boolean output r.add(a=True, b=False, output=out2) # non-boolean condition solution = r.solve(function) self.assertEqual(solution.implementation, code)
def test_rules_input_order_is_respected(self): """ First input has to be first on the final boolean expression. So programmers can use short circuiting to their advantage ;). Very useful when validating data. Changing input order will change expression order. """ code = ['def ordered_expression(a, b):', ' return a or b'] r = Rules(a=True, output=True) # boolean output r.add(b=True, output=True) # boolean condition solution = r.solve(f.ordered_expression, self) self.assertEqual(solution.implementation, code) code = ['def ordered_expression(a, b):', ' return a or b'] r = Rules(b=True, output=True) # boolean output r.add(a=True, output=True) # boolean condition solution = r.solve(f.ordered_expression, self) self.assertEqual(solution.implementation, code)
def test_factoring_with_code_var(self): """This is a hard test from test_code_generator.py, but additionally here it is added Code instances :)""" function = f.factor_code_with_code output_code = 'i * 2' code1_str = 'i == 9' code2_str = 'i == 7' code = [ 'def ' + function.__name__ + '(i):', '', ' if ' + code1_str + ' or ' + code2_str + ':', ' return ' + output_code, '', ' return False' ] i = Code() r = Rules(i == 9, output=i * 2) r.add(i == 7, output=i * 2) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_boolean_and_quasi_boolean_mix_false_values(self): """ Will make an if for the 0 case, while it will ignore the False case. """ code = [ 'def mix_false_values(a, b):', '', ' if a and not b or not a and b:', ' return 0', '', ' return False' ] r = Rules(a=False, b=True, output=0) # non-boolean output r.add(a=True, b=False, output=False) # boolean condition solution = r.solve(f.mix_false_values, self) self.assertEqual(solution.implementation, code) r = Rules(a=True, b=False, output=False) # non-boolean output r.add(a=False, b=True, output=0) # boolean condition solution = r.solve(f.mix_false_values, self) self.assertEqual(solution.implementation, code)
def test_factor_code_output(self): """ Tests that code output can be factored. """ function = f.factor_ordered_pieces_of_code output_code = '2*2' code1_str = 'isinstance(array[0], int)' code2_str = 'isinstance(array[1], int)' code = [ 'def ' + function.__name__ + '(array):', '', ' if ' + code1_str + ' or ' + code2_str + ':', ' return ' + output_code, '', ' return False' ] r = Rules(r1=s.Code(code_str=code1_str), output=s.Code(code_str=output_code)) r.add(s.Code(code_str=code2_str), output=s.Code(code_str=output_code)) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_factor_ordered_pieces_with_redundancy(self): """Tests that string output is factored, when inputs are given in more than one addition.""" function = f.factor_ordered_pieces_with_redundancy right_str = 'factoring!!!' code0_str = 'isinstance(array[0], int)' code1_str = 'isinstance(array[1], int)' code = [ 'def {}(array):'.format(function.__name__), '', ' if {}:'.format(code1_str), " return \"{}\"".format(right_str), '', ' return False' ] r = Rules(r1=s.Code(code_str=code0_str), r2=s.Code(code_str=code1_str), output=right_str) r.add(s.Code(code_str=code1_str), output=right_str) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_collision(self): """ Even though the rules are absurd and are a contradiction. The non deterministic model should choose and solve the problem at random between the identity ('return a') and its negation ('return not a'). """ r = Rules(a=True, output=True) # first condition r.add(a=True, output=False) # contradictory condition. r.solve(f.collision, self)
def test_factor_ordered_with_code(self): """This is a hard test from test_code_generator.py, but additionally here it is added Code vars :)""" function = f.factor_ordered_with_code right_str = 'i * j' code1_str = 'i != 0' code2_str = 'i < 1' code3_str = 'i > j' code = [ 'def ' + function.__name__ + '(i, j):', '', ' if {0} and {1} or {2}:'.format(code1_str, code2_str, code3_str), ' return ' + right_str, '', ' return False' ] i = Code() j = Code() r = Rules(i != 0, i < 1, output=i * j) r.add(i > j, output=i * j) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_right_code_input_order(self): """ For programmer convenience and to be able to use short circuiting. Code pieces on expressions will follow the same order as the input order. """ function = f.right_expression_order right_str = 'right order!!!' code1_str = 'len(array) > 1' code2_str = 'array[0]' code3_str = 'isinstance(array[0], int)' code = [ 'def ' + function.__name__ + '(array):', '', ' if ' + code1_str + ' and ' + code2_str + ' and ' + code3_str + ':', ' return ' + "\"" + right_str + "\"", '', ' return False' ] r = Rules(r1=s.Code(code_str=code1_str), r2=s.Code(code_str=code2_str), r3=s.Code(code_str=code3_str), output=right_str) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_factor_ordered_pieces_of_code(self): """ Tests that string output is factored, when inputs are given in more than one addition. """ function = f.factor_ordered_pieces_of_code right_str = 'factoring!!!' code1_str = 'isinstance(array[0], int)' code2_str = 'isinstance(array[1], int)' code3_str = 'isinstance(array[2], int)' code = [ 'def ' + function.__name__ + '(array):', '', ' if ' + code1_str + ' and ' + code2_str + ' or ' + code3_str + ':', ' return ' + "\"" + right_str + "\"", '', ' return False' ] r = Rules(r1=s.Code(code_str=code1_str), r2=s.Code(code_str=code2_str), output=right_str) r.add(s.Code(code_str=code3_str), output=right_str) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_inner_inputs_with_different_outputs(self): """ Inner inputs are not function arguments but are for example pieces of code, that act as inputs to the tables. Inside function 'return_solution', on module solver.py: On each table iteration the all_inputs variable has to be calculated inside the main function of solver.py This is because if not this test fails. """ function = f.many_outputs input1 = 'isinstance(a, int)' input2 = 'isinstance(a, str)' r = Rules(r1=Code(code_str=input1), output=1) r.add(r1=Code(code_str='isinstance(a, str)'), output=2) solution = r.solve(function, self) print(solution.implementation) # is taking the correct inputs self.assertEqual(solution.implementation[2], ' if {}:'.format(input1)) self.assertEqual(solution.implementation[5], ' if {}:'.format(input2))
def test_default_keyword(self): """ default keyword changes the last return from False to determined value. """ function = f.with_default_value out = 3 default = 5 code = [ 'def ' + function.__name__ + '(a, b):', '', ' if not a and b:', ' return ' + str(out), '', ' return ' + str(default) ] r = Rules(a=False, b=True, output=out, default=default) solution = r.solve(function, self) self.assertEqual(solution.implementation, code) r = Rules(a=False, b=True, output=out) r.add(default=default) solution = r.solve(function, self) self.assertEqual(solution.implementation, code)
def test_identity_representation(self): """There are 4 equivalent representations of the identity function: 1. Boring: >>> Rules(a=True, output=True) 2. Implicit True: >>> Rules(a=True) 3. Using Code() magic: >>> a = Code() >>> Rules(a, output=True) 4. Using both Code() magic and implicit True output: >>> a = Code() >>> Rules(a) lets test all representations!!! """ a = Code() solution = ['def {}(a):'.format(f.identity.__name__), ' return a'] r = Rules(a=True, output=True) s = r.solve(f.identity) self.assertEqual(s.implementation, solution) r = Rules(a=True) s = r.solve(f.identity) self.assertEqual(s.implementation, solution) r = Rules(a, output=True) s = r.solve(f.identity) self.assertEqual(s.implementation, solution) # TODO: pass this test: """
def from_table_to_ones(table): """ Gets the ones as a list of strings from a truth table like set, containing tuples. :param table: truth table :return: list containing bits. """ ones = [] for row in table: # case 1: when the output is explicit. if Rules.is_explicit(row): if row[1]: # only do it for true outputs.# TODO change for non booleans. ones.append(''.join(list(map(h.from_bool_to_bit, list(row[0]))))) else: # case 2: The output is an implicit True, inputs are in the row. ones.append(''.join(list(map(h.from_bool_to_bit, list(row))))) return ones