From 61b64066e0ebbd6b85012d04d237eb8c633c5211 Mon Sep 17 00:00:00 2001 From: Itamar Friedman Date: Mon, 6 Feb 2023 13:00:50 +0200 Subject: [PATCH] Fixed two issues and add sanity tests. Issue #1: super now calls the right class, #2: decoupled the initiatlization of call_center and employee. --- .../call_center/call_center.py | 34 +++++++-- .../call_center/tests/__init__.py | 0 .../call_center/tests/test_call_center.py | 76 +++++++++++++++++++ 3 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 solutions/object_oriented_design/call_center/tests/__init__.py create mode 100644 solutions/object_oriented_design/call_center/tests/test_call_center.py diff --git a/solutions/object_oriented_design/call_center/call_center.py b/solutions/object_oriented_design/call_center/call_center.py index 1d5e7bc6..1bfe73a1 100644 --- a/solutions/object_oriented_design/call_center/call_center.py +++ b/solutions/object_oriented_design/call_center/call_center.py @@ -12,12 +12,12 @@ class Rank(Enum): class Employee(metaclass=ABCMeta): - def __init__(self, employee_id, name, rank, call_center): + def __init__(self, employee_id, name, rank): self.employee_id = employee_id self.name = name self.rank = rank self.call = None - self.call_center = call_center + self.call_center = None def take_call(self, call): """Assume the employee will always successfully take the call.""" @@ -26,6 +26,7 @@ class Employee(metaclass=ABCMeta): self.call.state = CallState.IN_PROGRESS def complete_call(self): + assert self.call_center is not None self.call.state = CallState.COMPLETE self.call_center.notify_call_completed(self.call) @@ -34,11 +35,15 @@ class Employee(metaclass=ABCMeta): pass def _escalate_call(self): + assert self.call_center is not None self.call.state = CallState.READY call = self.call self.call = None self.call_center.notify_call_escalated(call) + def set_call_center(self, call_center): + self.call_center = call_center + class Operator(Employee): @@ -53,7 +58,7 @@ class Operator(Employee): class Supervisor(Employee): def __init__(self, employee_id, name): - super(Operator, self).__init__(employee_id, name, Rank.SUPERVISOR) + super(Supervisor, self).__init__(employee_id, name, Rank.SUPERVISOR) def escalate_call(self): self.call.level = Rank.DIRECTOR @@ -63,7 +68,7 @@ class Supervisor(Employee): class Director(Employee): def __init__(self, employee_id, name): - super(Operator, self).__init__(employee_id, name, Rank.DIRECTOR) + super(Director, self).__init__(employee_id, name, Rank.DIRECTOR) def escalate_call(self): raise NotImplementedError('Directors must be able to handle any call') @@ -87,10 +92,12 @@ class Call(object): class CallCenter(object): def __init__(self, operators, supervisors, directors): - self.operators = operators - self.supervisors = supervisors - self.directors = directors + self.operators = [] + self.supervisors = [] + self.directors = [] self.queued_calls = deque() + for employee in operators + supervisors + directors: + self.add_employee(employee) def dispatch_call(self, call): if call.rank not in (Rank.OPERATOR, Rank.SUPERVISOR, Rank.DIRECTOR): @@ -102,6 +109,7 @@ class CallCenter(object): employee = self._dispatch_call(call, self.supervisors) if call.rank == Rank.DIRECTOR or employee is None: employee = self._dispatch_call(call, self.directors) + if employee is None: self.queued_calls.append(call) @@ -112,6 +120,18 @@ class CallCenter(object): return employee return None + def add_employee(self, employee: Employee): + if isinstance(employee, Operator): + self.operators.append(employee) + elif isinstance(employee, Supervisor): + self.supervisors.append(employee) + elif isinstance(employee, Director): + self.directors.append(employee) + else: + raise ValueError('Invalid employee type: {}'.format(type(employee))) + employee.set_call_center(self) + + def notify_call_escalated(self, call): pass diff --git a/solutions/object_oriented_design/call_center/tests/__init__.py b/solutions/object_oriented_design/call_center/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/solutions/object_oriented_design/call_center/tests/test_call_center.py b/solutions/object_oriented_design/call_center/tests/test_call_center.py new file mode 100644 index 00000000..f4da88f4 --- /dev/null +++ b/solutions/object_oriented_design/call_center/tests/test_call_center.py @@ -0,0 +1,76 @@ + +# test_call_center.py - Generated by CodiumAI + +import pytest +from call_center.call_center import Operator, Supervisor, Director, Call, CallCenter, Rank + +""" +Code Analysis: +- The CallCenter class is used to manage calls in a call center. +- It takes three parameters: operators, supervisors, and directors. +- The queued_calls attribute is a deque object, which is a double-ended queue. +- The dispatch_call() method is used to assign a call to an employee based on the call's rank. +- If an employee is not available, the call is added to the queued_calls deque. +- The _dispatch_call() method is used to assign a call to an employee. +- The notify_call_escalated() and notify_call_completed() methods are used to notify the call center when a call is escalated or completed. +- The dispatch_queued_call_to_newly_freed_employee() method is used to assign a queued call to an employee who has just become available. +""" + +""" +Test Plan: +- test_dispatch_call(): tests that the dispatch_call() method assigns the call to the correct employee based on the call's rank +- test_dispatch_call_with_no_available_employee(): tests that the dispatch_call() method adds the call to the queued_calls deque if no employee is available +- test_add_employee(): tests that the add_employee() method adds the employee to the correct list based on the employee's type + +""" + +class TestCallCenter(): + + def setup_method(self, method): + self.operators = [Operator(1, 'John'), Operator(2, 'Jane')] + self.supervisors = [Supervisor(3, 'Bob')] + self.directors = [Director(4, 'Alice')] + self.call_center = CallCenter(self.operators, self.supervisors, self.directors) + + def test_dispatch_call(self): + call = Call(Rank.OPERATOR) + self.call_center.dispatch_call(call) + assert self.operators[0].call == call + + call = Call(Rank.SUPERVISOR) + self.call_center.dispatch_call(call) + assert self.supervisors[0].call == call + + call = Call(Rank.DIRECTOR) + self.call_center.dispatch_call(call) + assert self.directors[0].call == call + + def test_dispatch_call_with_no_available_employee(self): + for employee in self.operators + self.supervisors + self.directors: + employee.take_call(Call(Rank.OPERATOR)) + assert employee.call is not None + + call = Call(Rank.OPERATOR) + self.call_center.dispatch_call(call) + assert len(self.call_center.queued_calls) == 1 + + + def test_add_employee(self): + operator = Operator(5, 'Tom') + supervisor = Supervisor(6, 'Jerry') + director = Director(7, 'Sally') + + self.call_center.add_employee(operator) + assert operator in self.call_center.operators + + self.call_center.add_employee(supervisor) + assert supervisor in self.call_center.supervisors + + self.call_center.add_employee(director) + assert director in self.call_center.directors + + + + + +