from otree.api import Currency as c, currency_range, SubmissionMustFail from . import pages from ._builtin import Bot from .models import Constants import test_cases as tc import random as r # FOR ALPHA/BETA TESTING class PlayerBot(Bot): """"This class represents a virtual player that will input the values that each page requires and that allows to test if there are errors in a specific page or field. -Yield statements will change the value of the fields -Assert statements check if the field values have a specific value or not -SubmissionMustFail stops the game if an invalid value submitted has been accepted There are two main modes for the bots that are going to be checked at the same time *alpha: They check if the game runs with values that shouldn't be accepted by each variable. It checks: **inside the boundaries: checks for errors using inside the boundaries **in the boundaries: checks for errors using the boundary values (Because this task doesn't have fixed values predefined as answers, the fields should accept this values. This is not the case for the Practice and Quiz tasks) **outside the boundaries: checks for errors using values outside the boundaries **different types of values: checks if the values that has been inputted are the same type of the respective variables *beta: They check how the game would run in a real environment with a big amount of players. To do this testing, its only needed to run a huge number of bots. """ def play_round(self): tests_for_lender = tc.lender_cases_new tests_for_borrower = tc.borrower_cases_new if self.player.role() == 'lender': # VARIABLE: loan # Invalid value of the same type variable = 'loan' boundaries = tc.bounds_game if tests_for_lender['loan'] in boundaries: print('A bound is going to be used for the variable {}'.format(variable)) out_of_bounds = tc.out_of_bounds_game for out in out_of_bounds: yield SubmissionMustFail(pages.Loan_Amount, {'loan': out}) # Invalid value from a different type invalids = tc.type_errors_integer for invalid in invalids: yield SubmissionMustFail(pages.Loan_Amount, {'loan': invalid}) # Valid answer yield (pages.Loan_Amount, {'loan': tests_for_lender['loan']}) assert self.group.loan == tests_for_lender['loan'] if Constants.contract_enforcement is False: if self.group.accept_loan == 'Yes': # VARIABLE: satisfied # Invalid value of the same type out_of_bounds = ['a'] for out in out_of_bounds: yield SubmissionMustFail(pages.Collateral_Decision, {'satisfied': out}) # Invalid value from a different type invalids = tc.type_errors_char for invalid in invalids: yield SubmissionMustFail(pages.Collateral_Decision, {'satisfied': invalid}) # Valid answer yield (pages.Collateral_Decision, {'satisfied': tests_for_lender['satisfied']}) assert self.group.satisfied == tests_for_lender['satisfied'] if self.group.satisfied == 'No': recovered_collateral_aux = r.SystemRandom().randrange(0, self.group.collateral_after_fee) # VARIABLE: recovered_collateral # Invalid value of the same type variable = 'recovered_collateral' boundaries = [0, self.group.collateral_after_fee] if tests_for_lender['loan'] in boundaries: print('A bound is going to be used for the variable {}'.format(variable)) out_of_bounds = [-1, self.group.collateral_after_fee+1] for out in out_of_bounds: yield SubmissionMustFail(pages.Seize_Collateral, {'recovered_collateral': out}) # Invalid value from a different type invalids = tc.type_errors_integer for invalid in invalids: yield SubmissionMustFail(pages.Seize_Collateral, {'recovered_collateral': invalid}) # Valid answer yield (pages.Seize_Collateral, {'recovered_collateral': recovered_collateral_aux}) assert self.group.recovered_collateral == recovered_collateral_aux else: if self.group.accept_loan == 'Yes': yield (pages.Collateral_Decision) yield (pages.Seize_Collateral) elif self.player.role() == 'borrower': # VARIABLE: collateral # Invalid value of the same type variable = 'collateral' boundaries = tc.bounds_game if tests_for_borrower['collateral'] in boundaries: print('A bound is going to be used for the variable {}'.format(variable)) out_of_bounds = tc.out_of_bounds_game for out in out_of_bounds: yield SubmissionMustFail(pages.Collateral_Offer, {'collateral': out}) # Invalid value from a different type invalids = tc.type_errors_integer for invalid in invalids: yield SubmissionMustFail(pages.Collateral_Offer, {'collateral': invalid}) # Valid answer yield (pages.Collateral_Offer, {'collateral': tests_for_borrower['collateral']}) assert self.group.collateral == c(tests_for_borrower['collateral']) # VARIABLE: accept_loan # Invalid value of the same type out_of_bounds = ['a'] for out in out_of_bounds: yield SubmissionMustFail(pages.Loan_Package, {'accept_loan': out}) # Invalid value from a different type invalids = tc.type_errors_char for invalid in invalids: yield SubmissionMustFail(pages.Loan_Package, {'accept_loan': invalid}) # Valid answer yield (pages.Loan_Package, {'accept_loan': tests_for_borrower['accept_loan']}) assert self.group.accept_loan == tests_for_borrower['accept_loan'] if self.group.accept_loan == 'Yes': repayment_aux = r.SystemRandom().randrange(0, Constants.productivity * self.group.loan) # VARIABLE: repayment # Invalid value of the same type variable = 'repayment' boundaries = [0, Constants.productivity * self.group.loan] if repayment_aux in boundaries: print('A bound is going to be used for the variable {}'.format(variable)) out_of_bounds = [-1, Constants.productivity * self.group.loan + 1] for out in out_of_bounds: yield SubmissionMustFail(pages.Realize_Return, {'repayment': out}) # Invalid value from a different type invalids = tc.type_errors_integer for invalid in invalids: yield SubmissionMustFail(pages.Realize_Return, {'repayment': invalid}) # Valid answer yield (pages.Realize_Return, {'repayment': repayment_aux}) assert self.group.repayment == c(repayment_aux) else: print('There are only two roles: Borrower and Lender. You ' 'are using another one that is not allowed.') yield (pages.Results) """ # CODE TEMPLATE FOR BOTS # VARIABLE: # Invalid value of the same type variable = '' boundaries = if in boundaries: print('A bound is going to be used for the variable {}'.format(variable)) out_of_bounds = for out in out_of_bounds: yield SubmissionMustFail(pages., {'': out}) # Invalid value from a different type invalids = for invalid in invalids: yield SubmissionMustFail(pages., {'': invalid}) # Valid answer """