def test_absolute_garbage(s: str) -> None: """ Test that none of the filters raise errors when absolute garbage input strings are passed in. """ print(s) cf = CustomerFilter() df = DurationFilter() lf = LocationFilter() # test that nothing crashes cf.apply(CUSTOMERS, CALL_LIST, s) df.apply(CUSTOMERS, CALL_LIST, s) lf.apply(CUSTOMERS, CALL_LIST, s)
def test_filters() -> None: """ Test the functionality of the filters. We are only giving you a couple of tests here, you should expand both the dataset and the tests for the different types of applicable filters """ customers = create_customers(test_dict) process_event_history(test_dict, customers) # Populate the list of calls: calls = [] hist = customers[0].get_history() # only consider outgoing calls, we don't want to duplicate calls in the test calls.extend(hist[0]) # The different filters we are testing filters = [DurationFilter(), CustomerFilter(), ResetFilter()] # These are the inputs to each of the above filters in order. # Each list is a test for this input to the filter filter_strings = [["L50", "G10", "L0", "50", "AA", ""], ["5555", "1111", "9999", "aaaaaaaa", ""], ["rrrr", ""]] # These are the expected outputs from the above filter application # onto the full list of calls expected_return_lengths = [[1, 2, 0, 3, 3, 3], [3, 3, 3, 3, 3], [3, 3]] for i in range(len(filters)): for j in range(len(filter_strings[i])): result = filters[i].apply(customers, calls, filter_strings[i][j]) assert len(result) == expected_return_lengths[i][j]
def test_location_filter_with_large_data() -> None: """ Test the functionality of the location filters. We are only giving you a couple of tests here, you should expand both the dataset and the tests for the different types of applicable filters """ # loading up the large data input_dictionary = import_data() customers = create_customers(input_dictionary) process_event_history(input_dictionary, customers) # Populate the list of calls: calls = [] for cust in customers: hist = cust.get_history() # only look at outgoing calls, we don't want to duplicate calls in test calls.extend(hist[0]) # The different filters we are testing filters = [CustomerFilter(), LocationFilter()] # These are the inputs to each of the above filters in order. # Each list is a test for this input to the filter filter_strings = [ # contents: non-existent id, valid id, valid id ["5555", "5524", "9210"], # contents: loc of one call, max and min, one cord out, letters, valid loc but no calls [ "-79.54717029563305, 43.58020061333403, -79.54717029563303, 43.58020061333405", # location of one call "-79.697878, 43.576959, -79.196382, 43.799568", # entire map "-80.697877, 43.576960, -79.196383, 43.799567", # one coordinate in not within range "hellolol, erferer, fefergerger, ferereeev", # isalpaha == true "-79.697878, 43.6882635, -79.196382, 43.799568", # half the map (this one took me hours to count) "-79.54717029563305,43.58020061333403,-79.54717029563303,43.58020061333405", # location of one call but no spaces "-79.54717029563305 , 43.58020061333403 , -79.54717029563303, 43.58020061333405", # ^ spaces "-79.196382, 43.799568, -79.697878, 43.576959", # both cross "-79.296382, 43.576959, -79.597878, 43.799568", # x coords cross "-79.697878, 43.576959, -79.196382, 43.499568", # y coords cross "-80.697877, 69.576960, -89.196383, 69.799567", # all coords not within range "hellolol, erferer, fefergergerferereeev", # alpha + nums "#@%#@%#@%,#%@#%@#%,#%#@%#@%#@$%#@%", # symbols "", # empty "SDF(*@$)(*&#!)(*&#HFLKDSJF:LDSJFLKJDSF", # no commas " " # just spaces....... ] ] # These are the expected outputs from the above filter application # onto the full list of calls expected_return_lengths = [[1000, 45, 33], [ 1, 1000, 1000, 1000, 755, 1000, 1, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000 ]] for i in range(len(filters)): for j in range(len(filter_strings[i])): result = filters[i].apply(customers, calls, filter_strings[i][j]) assert len(result) == expected_return_lengths[i][j]
def test_combined_filters() -> None: log = create_task4_log() customers = create_customers(log) process_event_history(log, customers) all_calls = [] for c in customers: hist = c.get_history() all_calls.extend(hist[0]) fil = LocationFilter() filtered = fil.apply(customers, all_calls, f'{x2}, {y3}, {x2}, {y3}') fil = DurationFilter() filtered = fil.apply(customers, filtered, f'G{69 * 60 - 1}') filtered = fil.apply(customers, filtered, f'L{69 * 60 + 1}') assert len(filtered) == 3 count = 0 for call in filtered: assert call.src_number == '001-3111' if call.time.month == 1: count += 1 assert count == 2 fil = CustomerFilter() filtered = fil.apply(customers, all_calls, "1020") fil = DurationFilter() filtered = fil.apply(customers, filtered, f'G{10 * 60 - 1}') filtered = fil.apply(customers, filtered, f'L{130 * 60 + 1}') for call in filtered: assert 10 * 60 - 1 < call.duration < 130 * 60 + 1 print( f'src: {call.src_number}, dst: {call.dst_number}, dur: {call.duration}' ) assert len(filtered) == 23 + 11 + 6 fil = LocationFilter() filtered = fil.apply(customers, all_calls, f'{x3}, {y2}, {x3}, {y2}') #2101 fil = CustomerFilter() filtered = fil.apply(customers, filtered, "1002") assert len(filtered) == 3 * 2 * 3 for call in filtered: assert call.src_number[4:] == '1002' or call.src_number[4:] == '2101' assert fil.apply(customers, filtered, "3111") == [] fil = DurationFilter() assert fil.apply(customers, filtered, 'L60') == []
def test_customer_filter(id: int): """ Test that CustomerFilter works in the general case - with (more or less) valid inputs, aka 4 digit numerical customer IDs. Customer IDs may not belong to any customer. """ filt = CustomerFilter() results = filt.apply(CUSTOMERS, CALL_LIST, str(id)) cust = None for c in CUSTOMERS: if c.get_id() == id: cust = c break if cust is None: # if no customer has the ID, the original dataset should be returned assert results == CALL_LIST else: # if a customer has the ID, every call in the results of the filter # should involve the customer as either the source or destination for c in results: assert c.src_number in cust or c.dst_number in cust
def test_customer_filter() -> None: log = create_pure_log() customers = create_customers(log) process_event_history(log, customers) all_calls = [] for c in customers: hist = c.get_history() all_calls.extend(hist[0]) fil = CustomerFilter() invalid_inputs = [ '', 'dskljgdf', '69.69', 'd1200', 'L200', '-79.6, 43.3, -79.5, 43.4', '3690', ' ' ] for input in invalid_inputs: filtered = fil.apply(customers, all_calls, input) assert filtered == all_calls line_of_customer = ['100-2101', '001-2101'] filtered = fil.apply(customers, all_calls, '2101') for call in filtered: assert call.src_number in line_of_customer \ or call.dst_number in line_of_customer assert loc[2101] == call.src_loc or loc[2101] == call.dst_loc
def test_task4() -> None: # Filtering input_dictionary = import_data() customers = create_customers(input_dictionary) process_event_history(input_dictionary, customers) # Populate the list of calls: calls = [] for customer in customers: hist = customer.get_history() calls.extend(hist[0]) # The different filters we are testing # You need write LocationFilter test yourself filters = [ DurationFilter(), CustomerFilter(), ResetFilter() ] # These are the inputs to each of the above filters in order. # Each list is a test for this input to the filter filter_strings = [ ["L50", "G10", "L0", "50", "AA", "", "L100"], ["5555", "1111", "6020", "7930", "3087", "5524", "abc", ""], ["rrrr", ""] ] # These are the expected outputs from the above filter application # onto the full list of calls expected_return_lengths = [ [122, 975, 0, 1000, 1000, 1000, 261], [1000, 1000, 59, 22, 22, 45, 1000, 1000], [1000, 1000] ] for i in range(len(filters)): for j in range(len(filter_strings[i])): result = filters[i].apply(customers, calls, filter_strings[i][j]) assert len(result) == expected_return_lengths[i][j], str(filters[i].__class__.__name__) + ", with keyword " + filter_strings[i][j] + " produce wrong result"
def handle_window_events(self, customers: List[Customer], drawables: List[Call]) \ -> List[Call]: """Handle any user events triggered through the pygame window. The <drawables> are the objects currently displayed, while the <customers> list contains all customers from the input data. Return a new list of Calls, according to user input actions. """ new_drawables = drawables for event in pygame.event.get(): if event.type == pygame.QUIT: self._quit = True elif event.type == pygame.KEYDOWN: f = None num_threads = 1 if event.unicode == "d": f = DurationFilter() elif event.unicode == "l": f = LocationFilter() elif event.unicode == "c": f = CustomerFilter() elif event.unicode == "r": f = ResetFilter() num_threads = 1 if f is not None: def result_wrapper(fun: Callable[ [List[Customer], List[Call], str], List[Call]], customers: List[Customer], data: List[Call], filter_string: str, res: List) -> None: """A final wrapper to return the result of the operation """ res.append(fun(customers, data, filter_string)) def threading_wrapper(customers: List[Customer], data: List[Call], filter_string: str) -> List[Call]: """A wrapper for the application of filters with threading """ chunk_sz_calls = math.ceil( (len(data) + num_threads - 1) / num_threads) print("Num_threads:", num_threads) print("Chunk_calls:", chunk_sz_calls) threads = [] results = [] for i in range(num_threads): res = [] results.append(res) t = threading.Thread( target=result_wrapper, args=(f.apply, customers, data[i * chunk_sz_calls:(i + 1) * chunk_sz_calls], filter_string, res)) t.daemon = True t.start() threads.append(t) # f.apply(customers, data, filter_string) # Wait to finish for t in threads: t.join() # Now reconstruct the data new_data = [] for res in results: new_data.extend(res[0]) return new_data new_drawables = self.entry_window(str(f), customers, drawables, threading_wrapper) # Perform the billing for a selected customer: if event.unicode == "m": try: def get_customer(customers: List[Customer], found_customer: List[Customer], input_string: str) -> None: """ A helper to find the customer specified in the input string appends to the found_customer the matching customer """ try: for c in customers: if c.get_id() == int(input_string): found_customer.append(c) except ValueError: pass customer = [] self.entry_window( "Generate the bill for the customer " "with ID:", customers, customer, get_customer) if len(customer) == 0: raise ValueError # Just want to return the parsed input string def get_input_date(customer: List[Customer], drawables: List[Call], input_string: str) \ -> Optional[List[int]]: """ A helper to get the input date """ try: return [ int(s.strip()) for s in input_string.split(',') ] except ValueError: return None date = self.entry_window( "Bill month and year: " "month, year", customers, drawables, get_input_date) if date is None or date == ([], []): raise ValueError customer[0].print_bill(date[0], date[1]) except ValueError: print("ERROR: bad formatting for input string") except IndexError: print("Customer not found") elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: self._mouse_down = True elif event.button == 4: self._map.zoom(-0.1) elif event.button == 5: self._map.zoom(0.1) elif event.type == pygame.MOUSEBUTTONUP: self._mouse_down = False elif event.type == pygame.MOUSEMOTION: if self._mouse_down: self._map.pan(pygame.mouse.get_rel()) else: pygame.mouse.get_rel() return new_drawables