diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c8e4a48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +venv +.DS_Store +*.pyc diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..255a9f4 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +de.devboost.natspec.example.python \ No newline at end of file diff --git a/.idea/de.devboost.natspec.example.python.iml b/.idea/de.devboost.natspec.example.python.iml new file mode 100644 index 0000000..a34a857 --- /dev/null +++ b/.idea/de.devboost.natspec.example.python.iml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..1b4c54e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d767a1a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/other.xml b/.idea/other.xml new file mode 100644 index 0000000..a7f0eb1 --- /dev/null +++ b/.idea/other.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/testrunner.xml b/.idea/testrunner.xml new file mode 100644 index 0000000..0d97b74 --- /dev/null +++ b/.idea/testrunner.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..def6a6a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..810d0d3 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1399457712594 + 1399457712594 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..86e9bfc --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + de.devboost.natspec.example.python + + + + + + org.python.pydev.PyDevBuilder + + + + + de.devboost.natspec.resource.natspec.builder + + + + + + org.python.pydev.pythonNature + de.devboost.natspec.resource.natspec.nature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..037bd25 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,8 @@ + + + +/${PROJECT_DIR_NAME} + +python 2.7 +Default + diff --git a/.svn/entries b/.svn/entries new file mode 100644 index 0000000..3cacc0b --- /dev/null +++ b/.svn/entries @@ -0,0 +1 @@ +12 \ No newline at end of file diff --git a/.svn/format b/.svn/format new file mode 100644 index 0000000..3cacc0b --- /dev/null +++ b/.svn/format @@ -0,0 +1 @@ +12 \ No newline at end of file diff --git a/.svn/pristine/03/033e7a2a281fed1f658eae89afff72756789b9b1.svn-base b/.svn/pristine/03/033e7a2a281fed1f658eae89afff72756789b9b1.svn-base new file mode 100644 index 0000000..95d1b9b --- /dev/null +++ b/.svn/pristine/03/033e7a2a281fed1f658eae89afff72756789b9b1.svn-base @@ -0,0 +1,72 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class OverbookSeatNumber(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/overbook_seat_number.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # with 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Given a passenger Jane Doe + passenger_Jane_Doe = self.test_support.given_a_passenger(u("Jane"), u("Doe")) + + # Book seat for Jane Doe at LH-1234 + operationStatus_Jane_Doe_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Doe_LH_1234) + + # Given a passenger Jim Doe + passenger_Jim_Doe = self.test_support.given_a_passenger(u("Jim"), u("Doe")) + + # Book seat for Jim Doe at LH-1234 + operationStatus_Jim_Doe_LH_1234 = self.test_support.book_seat_for(u("Jim"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jim_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/03/0368ff037151ba04235d1b8819766ea0f97690be.svn-base b/.svn/pristine/03/0368ff037151ba04235d1b8819766ea0f97690be.svn-base new file mode 100644 index 0000000..1ec539c --- /dev/null +++ b/.svn/pristine/03/0368ff037151ba04235d1b8819766ea0f97690be.svn-base @@ -0,0 +1,12 @@ +from service.validation.support import ValidationSupport +class Rules(object): + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/service/validation/rules.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + + return self.validation_support.status \ No newline at end of file diff --git a/.svn/pristine/0f/0f7f11a494b89b1134d2041d551789c4ebae09d3.svn-base b/.svn/pristine/0f/0f7f11a494b89b1134d2041d551789c4ebae09d3.svn-base new file mode 100644 index 0000000..10705ba --- /dev/null +++ b/.svn/pristine/0f/0f7f11a494b89b1134d2041d551789c4ebae09d3.svn-base @@ -0,0 +1,18 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + With 2 free seats + +Given a passenger John Doe + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// cancel first passenger +Cancel seat for John Doe at LH-1234 + Assume a valid ticket is issued + +Cancel seat for John Doe at LH-1234 + Assume no valid ticket is issued diff --git a/.svn/pristine/2f/2fbb15a700985245d3f91083b73c0e33c16021dd.svn-base b/.svn/pristine/2f/2fbb15a700985245d3f91083b73c0e33c16021dd.svn-base new file mode 100644 index 0000000..e2e2116 --- /dev/null +++ b/.svn/pristine/2f/2fbb15a700985245d3f91083b73c0e33c16021dd.svn-base @@ -0,0 +1,90 @@ +class Entity(object): + # A global counter that holds the next available entity ID. + _counter = 0 + + def __init__(self): + """Creates a new entity and initialized its ID.""" + Entity._counter += 1 + self.id = Entity._counter + + +class NamedEntity(Entity): + """This is a super class for all entities that carry a name.""" + def __init__(self, name): + super(NamedEntity, self).__init__() + self.name = name + + +class Passenger(Entity): + """A Passenger object represents a person who can be booked on flights.""" + + def __init__(self, first_name, last_name): + """Creates a new passenger with the given first and last name, having an initial ago of zero. + :param firstname: the first name of the passenger. + :param lastname: the last name of the passenger. + """ + super(Passenger, self).__init__() + self.first_name = first_name + self.last_name = last_name + self.age = 0 + +class Flight(NamedEntity): + """A Flight represents the opportunity to travel from one airport to another. + Each Flight is executed using a particular type of airplane and holds a limited amount of passengers. + """ + + def __init__(self, name): + """Creates a new flight with the given name. + :param name: the new name for the flight. + """ + super(Flight, self).__init__(name) + self.__airplane = None + self.passenger_ids = [] + self.__free_seats = 0 + + @property + def airplane(self): + return self._airplane + + @airplane.setter + def airplane(self, value): + self.__airplane = value + self.__free_seats = value.total_seats + + @property + def free_seats(self): + return self.__free_seats - len(self.passenger_ids) + + @free_seats.setter + def free_seats(self, value): + self.__free_seats = value + + def has_passenger(self, passenger): + return passenger.id in self.passenger_ids + + def add_passenger(self, passenger): + self.passenger_ids.append(passenger.id) + + def remove_passenger(self, passenger): + if passenger.id in self.passenger_ids: + self.passenger_ids.remove(passenger.id) + return True + return False + + +class AirplaneType(NamedEntity): + """An AirplaneType represents a specific typo of airplane which is + characterized by its name and a number of total seats. + """ + + def __init__(self, name): + """Creates a new AirplaneType entity with the given name. + :param name: the name of the type of airplane. + """ + super(AirplaneType, self).__init__(name) + self.total_seats = 0 + + + + + diff --git a/.svn/pristine/30/302576028730c94a129ddb37be9c8a0d12e97668.svn-base b/.svn/pristine/30/302576028730c94a129ddb37be9c8a0d12e97668.svn-base new file mode 100644 index 0000000..3aaad00 --- /dev/null +++ b/.svn/pristine/30/302576028730c94a129ddb37be9c8a0d12e97668.svn-base @@ -0,0 +1,141 @@ +from natspec_utils.decorators import TextSyntax + + +class TestSupport(object): + """This class contains all test support methods that are required to make the + example specifications executable. Methods that are decorated with the + TextSyntax decorator are recognized by NatSpec. + This class is parameterized by two parameters that are passed to the + constructor (the service class which implements the business logic and the + entity manager that provides access to all entities). + """ + + def __init__(self, service, persistence_context, test_case): + """Creates a new {@link TestSupport} instance. This constructor is usually + invoked from a {@link _NatSpecTemplate}. + :param service: the business service logic. + :param persistence_context: the entity manager to access entities. + :param test_case: the test case we are running, needed to access asserts + """ + self.service = service + self.persistence_context = persistence_context + self.test_case = test_case + self.passengers = {} + self.flights = {} + self.airplane_types = {} + + @TextSyntax(["Given a Passenger #1 #2"], types=["str", "str"], return_type="Passenger") + def given_a_passenger(self, first_name, last_name): + """Creates a new passenger. + :param first_name: the first name of the passenger. + :param last_name: the last name of the passenger. + :returns: the newly created passenger. + """ + passenger = self.persistence_context.create_passenger(first_name, last_name) + self.passengers.update({"{0} {1}".format(first_name, last_name): passenger}) + return passenger + + @TextSyntax("With age of #2 years", types=["Passenger", "int"]) + def with_age_of_years(self, passenger, age): + """Sets the age of the given passenger. The passenger is expected to be + contained in the implicit context (i.e., it must be created by a previous + sentence/test support method). The name of the passenger is not + explicitly required here, because there is no placeholder for the + passenger parameter (i.e., #1 is missing). + :param passenger: the passenger to set the age for. + :param age: the new age for the passenger. + """ + passenger.age = age + + @TextSyntax(["Given an Airplane #1"], types=["str"], return_type="AirplaneType") + def given_an_airplane(self, name): + """Creates a new type of airplane. + :param name: the name of the type of airplane. + :returns: the newly created airplane type. + """ + airplane_type = self.persistence_context.create_airplane_type(name) + self.airplane_types.update({name: airplane_type}) + return airplane_type + + @TextSyntax(["Given a flight #1"], types=["str", ], return_type="Flight") + def given_a_flight(self, name): + """Creates a new flight. + :param name: the name of the flight. + :returns: the newly created flight. + """ + flight = self.persistence_context.create_flight(name) + self.flights.update({name: flight}) + return flight + + @TextSyntax("that is executed using a #1", types=["str", "Flight"]) + def that_is_executed_using_a(self, airplane_name, flight): + """Assigns the type of airplane that is used to execute the last mentioned flight. + :param airplane_name: the type of airplane to assign to the flight. + :param flight: the flight for which to set the airplane type (must be available from context). + """ + airplane = self.airplane_types.get(airplane_name) + flight.airplane = airplane + + @TextSyntax("With #1 free seats", types=["int", "Flight"]) + def with_free_seats(self, free_seats, flight): + """Sets the number of free seats for the flight mentioned last. + :param free_seats: the number of free seats + :param flight: the flight to set the seats for (must be available from context). + """ + flight.free_seats = free_seats + + @TextSyntax("Book seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def book_seat_for(self, first_name, last_name, flight_name): + """Tries to book a seat for the given passenger on the given flight. + :param first_name: the first name of passenger to book the flight for + :param last_name: the last name of passenger to book the flight for + :param flight_name: the name of flight to book the seat on. + :returns: the status of the booking operation which can be validated using + assume_valid_ticket(OperationStatus) or + assume_no_valid_ticked_is_issued(OperationStatus). + """ + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get(flight_name) + return self.service.book_seat(passenger, flight) + + @TextSyntax("Cancel seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def cancel_seat_for(self, first_name, last_name, flight_name): + """Tries to cancel the given passenger on the given flight. + :param first_name: the first name of passenger to book the flight for + :param last_name: the last name of passenger to book the flight for + :param flight_name: the name of flight to book the seat on. + :returns: the status of the cancel operation which can be validated using + assume_valid_ticket(OperationStatus) or + assume_no_valid_ticked_is_issued(OperationStatus). + """ + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get("{0}".format(flight_name)) + return self.service.cancel_seat(passenger, flight) + + @TextSyntax(["Assume a valid ticket is issued", "Assume cancellation successful"], types=["OperationStatus"]) + def assume_valid_ticket(self, status): + """Checks that the validity of the last operation is True + (i.e., that the operation was successful). This method has a TextSyntax decorator + with multiple patterns (first arg) to map multiple sentences to this method. + :param status: the status of the last operation (must be implicitly available from context). + """ + self.test_case.assertTrue(status.valid, msg=status.msg) + + @TextSyntax("Assume no valid ticket is issued", types=["OperationStatus"]) + def assume_no_valid_ticked_is_issued(self, status): + """Checks that the validity of the last executed business operations is False. + :param status: the status of the last operation (implicit parameter, not explicitly mentioned in sentence) + """ + self.test_case.assertFalse(status.valid, msg=status.msg) + + + @TextSyntax("Assume #1 has passenger #2", types=["Flight", "Passenger"]) + def assume_has_passenger(self, flight, passenger): + """Checks that the given passenger is booked for the given flight. Both the + flight and the passenger must be referenced explicitly. + :param flight: the flight to check + :param passenger: the passenger to check + """ + self.test_case.assertTrue(flight.has_passenger(passenger)) + + diff --git a/.svn/pristine/39/39e0595231116a13c8ad773377313b954a3398a6.svn-base b/.svn/pristine/39/39e0595231116a13c8ad773377313b954a3398a6.svn-base new file mode 100644 index 0000000..281acfc --- /dev/null +++ b/.svn/pristine/39/39e0595231116a13c8ad773377313b954a3398a6.svn-base @@ -0,0 +1,24 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + With 1 free seats + +Given a passenger John Doe +Given a passenger Jane Mejer + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// second passenger +Book seat for Jane Mejer at LH-1234 + Assume no valid ticket is issued + +// cancel first passenger +Cancel seat for John Doe at LH-1234 + Assume cancellation successful + +// rebook second passenger on now free set +Book seat for Jane Mejer at LH-1234 + Assume a valid ticket is issued diff --git a/.svn/pristine/3d/3d7bada97b45c25e921639fc40f1fc1538de0da4.svn-base b/.svn/pristine/3d/3d7bada97b45c25e921639fc40f1fc1538de0da4.svn-base new file mode 100644 index 0000000..07cdabd --- /dev/null +++ b/.svn/pristine/3d/3d7bada97b45c25e921639fc40f1fc1538de0da4.svn-base @@ -0,0 +1,20 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeatTwice(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/3f/3f651f40a18a93d31f75935b1fa0d69dd9608656.svn-base b/.svn/pristine/3f/3f651f40a18a93d31f75935b1fa0d69dd9608656.svn-base new file mode 100644 index 0000000..94e5727 --- /dev/null +++ b/.svn/pristine/3f/3f651f40a18a93d31f75935b1fa0d69dd9608656.svn-base @@ -0,0 +1,4 @@ +class OperationStatus(object): + def __init__(self, msg="", status=True): + self.msg = msg + self.valid = status \ No newline at end of file diff --git a/.svn/pristine/4b/4b4f209134389ee2ddbfedbd05fa6026986b7510.svn-base b/.svn/pristine/4b/4b4f209134389ee2ddbfedbd05fa6026986b7510.svn-base new file mode 100644 index 0000000..30a3a43 --- /dev/null +++ b/.svn/pristine/4b/4b4f209134389ee2ddbfedbd05fa6026986b7510.svn-base @@ -0,0 +1,20 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class OverbookSeatNumber(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/overbook_seat_number.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/4b/4b5d919f5509e01c2663f0b5df8ec8261cfffe8f.svn-base b/.svn/pristine/4b/4b5d919f5509e01c2663f0b5df8ec8261cfffe8f.svn-base new file mode 100644 index 0000000..ba848a1 --- /dev/null +++ b/.svn/pristine/4b/4b5d919f5509e01c2663f0b5df8ec8261cfffe8f.svn-base @@ -0,0 +1,13 @@ +// This scenario describes a simple booking process +// for an exemplary passenger + +Given a Passenger John Doe +Given an Airplane Boeing-787 + +Given a flight LH-1234 + that is executed using a Boeing-787 + With 200 free seats + +Book seat for John Doe at LH-1234 + +Assume a valid ticket is issued \ No newline at end of file diff --git a/.svn/pristine/4b/4b84ab3d95ee9b3b61da4a406b7cabd80aab8a38.svn-base b/.svn/pristine/4b/4b84ab3d95ee9b3b61da4a406b7cabd80aab8a38.svn-base new file mode 100644 index 0000000..94a56ba --- /dev/null +++ b/.svn/pristine/4b/4b84ab3d95ee9b3b61da4a406b7cabd80aab8a38.svn-base @@ -0,0 +1,9 @@ +class OperationStatus(object): + """Objects of type OperationStatus are used to capture the result of + business operations. Each result comprises of a message and a validity flag + which indicates success or failure of the operation. + """ + + def __init__(self, msg="", status=True): + self.msg = msg + self.valid = status \ No newline at end of file diff --git a/.svn/pristine/4b/4bb03f9d7db8d78616acee473d010dedca0d96a8.svn-base b/.svn/pristine/4b/4bb03f9d7db8d78616acee473d010dedca0d96a8.svn-base new file mode 100644 index 0000000..0dd91d2 --- /dev/null +++ b/.svn/pristine/4b/4bb03f9d7db8d78616acee473d010dedca0d96a8.svn-base @@ -0,0 +1,70 @@ +class Entity(object): + # A global counter that holds the next available entity ID. + _counter = 0 + + def __init__(self): + """Creates a new entity and initialized its ID.""" + Entity._counter += 1 + self.id = Entity._counter + + +class NamedEntity(Entity): + def __init__(self, name): + super(NamedEntity, self).__init__() + self.name = name + + +class Passenger(Entity): + def __init__(self, first_name, last_name): + super(Passenger, self).__init__() + self.first_name = first_name + self.last_name = last_name + self.age = 0 + +class Flight(NamedEntity): + def __init__(self, name): + super(Flight, self).__init__(name) + + self.__airplane = None + self.passenger_ids = [] + self.__free_seats = 0 + + @property + def airplane(self): + return self._airplane + + @airplane.setter + def airplane(self, value): + self.__airplane = value + self.__free_seats = value.total_seats + + @property + def free_seats(self): + return self.__free_seats - len(self.passenger_ids) + + @free_seats.setter + def free_seats(self, value): + self.__free_seats = value + + def has_passenger(self, passenger): + return passenger.id in self.passenger_ids + + def add_passenger(self, passenger): + self.passenger_ids.append(passenger.id) + + def remove_passenger(self, passenger): + if passenger.id in self.passenger_ids: + self.passenger_ids.remove(passenger.id) + return True + return False + + +class AirplaneType(NamedEntity): + def __init__(self, name): + super(AirplaneType, self).__init__(name) + self.total_seats = 0 + + + + + diff --git a/.svn/pristine/5a/5a9ed3df9efef9fae82bde66b113ae8d124f08c7.svn-base b/.svn/pristine/5a/5a9ed3df9efef9fae82bde66b113ae8d124f08c7.svn-base new file mode 100644 index 0000000..d46941c --- /dev/null +++ b/.svn/pristine/5a/5a9ed3df9efef9fae82bde66b113ae8d124f08c7.svn-base @@ -0,0 +1,20 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelAndRebookSeat(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_and_rebook_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/5d/5daf54df2af2ae4db398e3e9a6c99b80344db878.svn-base b/.svn/pristine/5d/5daf54df2af2ae4db398e3e9a6c99b80344db878.svn-base new file mode 100644 index 0000000..578cbcd --- /dev/null +++ b/.svn/pristine/5d/5daf54df2af2ae4db398e3e9a6c99b80344db878.svn-base @@ -0,0 +1,36 @@ +from service.validation.rules import Rules +from service.status import OperationStatus + +class AirlineService(object): + """The AirlineService provides very basic business functionality for the + airline domain. It allows to book seats for passengers on flights + and to cancel these seats. + """ + + def book_seat(self, passenger, flight): + """Tries to book a seat for the given passenger on the given flight. Before + the seat is actually booked some validation rules are checked to make + sure the constraints of the domain (e.g., that a passenger can book at + most one seat for a flight) are met. If one of the validation rules is + violated, this operation fails. + :param flight: the flight to book the seat on. + :param passenger: the passenger to book the seat for. + :returns: a status object representing the operations success (or failure). + """ + rules = Rules(flight, passenger) + status = rules.validate() + if status.valid: + flight.add_passenger(passenger) + return status + + def cancel_seat(self, passenger, flight): + """Cancels the seat booked by the given passenger on the given flight. This + operation can fail if the passenger has not booked a seat on the given + flight. + :param passenger: the passenger to cancel the seat for. + :param flight: the flight to cancel the seat on. + :returns: a status object representing the operations success (or failure). + """ + if flight.remove_passenger(passenger): + return OperationStatus("Passenger was removed", True) + return OperationStatus("Passenger was not booked on flight", False) \ No newline at end of file diff --git a/.svn/pristine/68/685911c54598042f7d86a63507470ac8387936e3.svn-base b/.svn/pristine/68/685911c54598042f7d86a63507470ac8387936e3.svn-base new file mode 100644 index 0000000..0635f12 --- /dev/null +++ b/.svn/pristine/68/685911c54598042f7d86a63507470ac8387936e3.svn-base @@ -0,0 +1,8 @@ +from service.validation.support import ValidationSupport +class _NatSpecTemplate(object): + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """ @MethodBody """ + return self.validation_support.status \ No newline at end of file diff --git a/.svn/pristine/6f/6f824ab29cab36565094cb899a3c69dd3504322c.svn-base b/.svn/pristine/6f/6f824ab29cab36565094cb899a3c69dd3504322c.svn-base new file mode 100644 index 0000000..21ec919 --- /dev/null +++ b/.svn/pristine/6f/6f824ab29cab36565094cb899a3c69dd3504322c.svn-base @@ -0,0 +1,16 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class _NatSpecTemplate(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ @MethodBody """ + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/70/707e2d830b9e02fe2d8959e0df52bdf20cbb8d64.svn-base b/.svn/pristine/70/707e2d830b9e02fe2d8959e0df52bdf20cbb8d64.svn-base new file mode 100644 index 0000000..286d563 --- /dev/null +++ b/.svn/pristine/70/707e2d830b9e02fe2d8959e0df52bdf20cbb8d64.svn-base @@ -0,0 +1,21 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class _NatSpecTemplate(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ @MethodBody """ + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/72/7208b39c09081a0357b727a62e00abaacbdc45a2.svn-base b/.svn/pristine/72/7208b39c09081a0357b727a62e00abaacbdc45a2.svn-base new file mode 100644 index 0000000..3709f1c --- /dev/null +++ b/.svn/pristine/72/7208b39c09081a0357b727a62e00abaacbdc45a2.svn-base @@ -0,0 +1,21 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + with 2 free seats + +Given a passenger John Doe + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// second passenger +Given a passenger Jane Doe + Book seat for Jane Doe at LH-1234 + Assume a valid ticket is issued + +// third passenger +Given a passenger Jim Doe + Book seat for Jim Doe at LH-1234 + Assume no valid ticket is issued \ No newline at end of file diff --git a/.svn/pristine/73/73bd9d09363c3cab9f4a106473016a7c673abcdb.svn-base b/.svn/pristine/73/73bd9d09363c3cab9f4a106473016a7c673abcdb.svn-base new file mode 100644 index 0000000..83f47ab --- /dev/null +++ b/.svn/pristine/73/73bd9d09363c3cab9f4a106473016a7c673abcdb.svn-base @@ -0,0 +1,16 @@ +from service.validation.rules import Rules +from service.status import OperationStatus + + +class AirlineService(object): + def book_seat(self, passenger, flight): + rules = Rules(flight, passenger) + status = rules.validate() + if status.valid: + flight.add_passenger(passenger) + return status + + def cancel_seat(self, passenger, flight): + if flight.remove_passenger(passenger): + return OperationStatus("Passenger was removed", True) + return OperationStatus("Passenger was not booked on flight", False) \ No newline at end of file diff --git a/.svn/pristine/81/8171a7d6c01a1ddc0f28a722612e19d785ce13b3.svn-base b/.svn/pristine/81/8171a7d6c01a1ddc0f28a722612e19d785ce13b3.svn-base new file mode 100644 index 0000000..616350a --- /dev/null +++ b/.svn/pristine/81/8171a7d6c01a1ddc0f28a722612e19d785ce13b3.svn-base @@ -0,0 +1,54 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeatTwice(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_787) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/85/85b1b1241cd7d08aeaec1d8cec75db99585e6de8.svn-base b/.svn/pristine/85/85b1b1241cd7d08aeaec1d8cec75db99585e6de8.svn-base new file mode 100644 index 0000000..2478004 --- /dev/null +++ b/.svn/pristine/85/85b1b1241cd7d08aeaec1d8cec75db99585e6de8.svn-base @@ -0,0 +1,15 @@ +// This scenario describes an erroneous booking example +// where the same passenger is booked twice for one flight + +Given a Passenger John Doe +Given an Airplane Boeing-787 +Given a flight LH-1234 + that is executed using a Boeing-787 + With 200 free seats + +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// Second booking for the same passenger should fail +Book seat for John Doe at LH-1234 + Assume no valid ticket is issued \ No newline at end of file diff --git a/.svn/pristine/93/93cf9800571991cd4c985b63962c9663e52aa916.svn-base b/.svn/pristine/93/93cf9800571991cd4c985b63962c9663e52aa916.svn-base new file mode 100644 index 0000000..cc018d6 --- /dev/null +++ b/.svn/pristine/93/93cf9800571991cd4c985b63962c9663e52aa916.svn-base @@ -0,0 +1,33 @@ +from service.status import OperationStatus +from natspec_utils.decorators import TextSyntax +class ValidationSupport(): + def __init__(self, flight, passenger): + self.flight = flight + self.passenger = passenger + self.status = OperationStatus() + + def set_invalid(self, msg): + self.status.valid = False + self.status.msg = msg + + @TextSyntax("Each Passenger can only be booked once.") + def check_unique_passenger(self): + if self.passenger.id in self.flight.passenger_ids: + self.set_invalid("A passenger can only be booked once for each flight.") + + @TextSyntax("There should be at least #1 free seats to handle overbooking.", types=["int"]) + def check_free_seats_with_buffer(self, overbooking_buffer): + if self.flight.free_seats < overbooking_buffer: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("There needs to be a free seat for the passenger.") + def check_free_seats(self): + if self.flight.free_seats < 1: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("The Passenger needs to be at least #1 years old.", types=["int"]) + def passenger_needs_to_be_at_least_years_old(self, minimal_age): + if self.passenger.age < minimal_age: + self.set_invalid("The passenger needs to be at least {0} years.".format(minimal_age)) + + diff --git a/.svn/pristine/9c/9cd1742dad5745fa11d674aa2f20dbc44bced1d1.svn-base b/.svn/pristine/9c/9cd1742dad5745fa11d674aa2f20dbc44bced1d1.svn-base new file mode 100644 index 0000000..06940f6 --- /dev/null +++ b/.svn/pristine/9c/9cd1742dad5745fa11d674aa2f20dbc44bced1d1.svn-base @@ -0,0 +1,27 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class _NatSpecTemplate(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ @MethodBody """ + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/a7/a7f43475f12c2bfd6a4ebbd04fdafe92535cd97c.svn-base b/.svn/pristine/a7/a7f43475f12c2bfd6a4ebbd04fdafe92535cd97c.svn-base new file mode 100644 index 0000000..4f359fd --- /dev/null +++ b/.svn/pristine/a7/a7f43475f12c2bfd6a4ebbd04fdafe92535cd97c.svn-base @@ -0,0 +1,50 @@ +from service.status import OperationStatus +from natspec_utils.decorators import TextSyntax +class ValidationSupport(): + """The ValidationSupport call defined all methods that are required to + execute the textual validation rules present in this example. + """ + + def __init__(self, flight, passenger): + """Creates a new instance of this class that can be used to validate the + given flight and passenger. + + :param flight: the flight to validate. + :param passenger: the passenger to validate. + """ + self.flight = flight + self.passenger = passenger + self.status = OperationStatus() + + def set_invalid(self, msg): + """Sets the status of this validation to invalid (failure) and adds the given message. + :param msg: the message to add. + """ + self.status.valid = False + self.status.msg = msg + + @TextSyntax("Each Passenger can only be booked once.") + def check_unique_passenger(self): + """Checks that the passenger has not already booked a seat on this flight.""" + if self.passenger.id in self.flight.passenger_ids: + self.set_invalid("A passenger can only be booked once for each flight.") + + @TextSyntax("There should be at least #1 free seats to handle overbooking.", types=["int"]) + def check_free_seats_with_buffer(self, overbooking_buffer): + """Checks that the given number of seats is held free.""" + if self.flight.free_seats < overbooking_buffer: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("There needs to be a free seat for the passenger.") + def check_free_seats(self): + """Checks that there is at least one seat available.""" + if self.flight.free_seats < 1: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("The Passenger needs to be at least #1 years old.", types=["int"]) + def passenger_needs_to_be_at_least_years_old(self, minimal_age): + """Checks that the passenger has at least the given age (in years).""" + if self.passenger.age < minimal_age: + self.set_invalid("The passenger needs to be at least {0} years.".format(minimal_age)) + + diff --git a/.svn/pristine/b0/b0a58c3d3226003bdca1cfd8fe36e5057a176e83.svn-base b/.svn/pristine/b0/b0a58c3d3226003bdca1cfd8fe36e5057a176e83.svn-base new file mode 100644 index 0000000..3b42876 --- /dev/null +++ b/.svn/pristine/b0/b0a58c3d3226003bdca1cfd8fe36e5057a176e83.svn-base @@ -0,0 +1,19 @@ +from service.validation.support import ValidationSupport + +class _NatSpecTemplate(object): + """This class serves as a template for validation rule classes that are written + in plain natural language. The template is instantiated by NatSpec for all + the .natspec files in this package. The @MethodBody placeholder + in validate() is replaced with the code that performs the actual validation. + See class Rules for a concrete example validation class. + This class is an example of applying NatSpec for non-testing purposes. + """ + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """Checks that all validation rules are met. + :returns: the status of the validation (i.e., success or failure). + """ + """ @MethodBody """ + return self.validation_support.status \ No newline at end of file diff --git a/.svn/pristine/b6/b6aa00adf118dc7b6e042537b3bc565b0cabd105.svn-base b/.svn/pristine/b6/b6aa00adf118dc7b6e042537b3bc565b0cabd105.svn-base new file mode 100644 index 0000000..b561c84 --- /dev/null +++ b/.svn/pristine/b6/b6aa00adf118dc7b6e042537b3bc565b0cabd105.svn-base @@ -0,0 +1 @@ +natspec_utils diff --git a/.svn/pristine/bb/bbedbb12b4dba55e7aa757e69c73197b33242279.svn-base b/.svn/pristine/bb/bbedbb12b4dba55e7aa757e69c73197b33242279.svn-base new file mode 100644 index 0000000..3e563bd --- /dev/null +++ b/.svn/pristine/bb/bbedbb12b4dba55e7aa757e69c73197b33242279.svn-base @@ -0,0 +1,66 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class OverbookSeatNumber(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/overbook_seat_number.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_737_600) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # with 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Given a passenger Jane Doe + passenger_Jane_Doe = self.test_support.given_a_passenger(u("Jane"), u("Doe")) + + # Book seat for Jane Doe at LH-1234 + operationStatus_Jane_Doe_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Doe_LH_1234) + + # Given a passenger Jim Doe + passenger_Jim_Doe = self.test_support.given_a_passenger(u("Jim"), u("Doe")) + + # Book seat for Jim Doe at LH-1234 + operationStatus_Jim_Doe_LH_1234 = self.test_support.book_seat_for(u("Jim"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jim_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/bf/bff463ed06e3bdc23a2570854f65cee858ad783a.svn-base b/.svn/pristine/bf/bff463ed06e3bdc23a2570854f65cee858ad783a.svn-base new file mode 100644 index 0000000..60010c6 --- /dev/null +++ b/.svn/pristine/bf/bff463ed06e3bdc23a2570854f65cee858ad783a.svn-base @@ -0,0 +1,54 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeat(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/c6/c6a51e8753a3c623c95586e376576606831c7f8d.svn-base b/.svn/pristine/c6/c6a51e8753a3c623c95586e376576606831c7f8d.svn-base new file mode 100644 index 0000000..df16336 --- /dev/null +++ b/.svn/pristine/c6/c6a51e8753a3c623c95586e376576606831c7f8d.svn-base @@ -0,0 +1,75 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelAndRebookSeat(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_and_rebook_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 1 free seats + self.test_support.with_free_seats(1, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given a passenger Jane Mejer + passenger_Jane_Mejer = self.test_support.given_a_passenger(u("Jane"), u("Mejer")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jane_Mejer_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume cancellation successful + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_12340 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Mejer_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/cb/cb257dd17bb8f12d6d222f190e9d79219b9f276d.svn-base b/.svn/pristine/cb/cb257dd17bb8f12d6d222f190e9d79219b9f276d.svn-base new file mode 100644 index 0000000..c227b18 --- /dev/null +++ b/.svn/pristine/cb/cb257dd17bb8f12d6d222f190e9d79219b9f276d.svn-base @@ -0,0 +1,69 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelAndRebookSeat(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_and_rebook_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_737_600) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 1 free seats + self.test_support.with_free_seats(1, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given a passenger Jane Mejer + passenger_Jane_Mejer = self.test_support.given_a_passenger(u("Jane"), u("Mejer")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jane_Mejer_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume cancellation successful + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_12340 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Mejer_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/cd/cd19710b605b40adb9fe207705bd040b6ca276da.svn-base b/.svn/pristine/cd/cd19710b605b40adb9fe207705bd040b6ca276da.svn-base new file mode 100644 index 0000000..347336e --- /dev/null +++ b/.svn/pristine/cd/cd19710b605b40adb9fe207705bd040b6ca276da.svn-base @@ -0,0 +1,60 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelSeatTwice(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_737_600) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12341 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12341) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/d0/d04643cf9d33d11f5522ec5e0f50305a9c175d3a.svn-base b/.svn/pristine/d0/d04643cf9d33d11f5522ec5e0f50305a9c175d3a.svn-base new file mode 100644 index 0000000..af71a62 --- /dev/null +++ b/.svn/pristine/d0/d04643cf9d33d11f5522ec5e0f50305a9c175d3a.svn-base @@ -0,0 +1,69 @@ +from natspec_utils.decorators import TextSyntax + + +class TestSupport(object): + def __init__(self, service, persistence_context, test_case): + self.service = service + self.persistence_context = persistence_context + self.test_case = test_case + self.passengers = {} + self.flights = {} + self.airplane_types = {} + + @TextSyntax(["Given a Passenger #1 #2"], types=["str", "str"], return_type="Passenger") + def given_a_passenger(self, first_name, last_name): + passenger = self.persistence_context.create_passenger(first_name, last_name) + self.passengers.update({"{0} {1}".format(first_name, last_name): passenger}) + return passenger + + @TextSyntax("With age of #2 years", types=["Passenger", "int"]) + def with_age_of_years(self, passenger, age): + passenger.age = age + + @TextSyntax(["Given an Airplane #1"], types=["str"], return_type="AirplaneType") + def given_an_airplane(self, name): + airplane_type = self.persistence_context.create_airplane_type(name) + self.airplane_types.update({name: airplane_type}) + return airplane_type + + @TextSyntax(["Given a flight #1"], types=["str", "AirplaneType"], return_type="Flight") + def given_a_flight(self, name, airplane): + flight = self.persistence_context.create_flight(name) + flight.airplane = airplane + self.flights.update({name: flight}) + return flight + + @TextSyntax("that is executed using a #1", types=["str", "Flight"]) + def that_is_executed_using_a(self, airplane_name, flight): + airplane = self.airplane_types.get(airplane_name) + flight.airplane = airplane + + @TextSyntax("With #1 free seats", types=["int", "Flight"]) + def with_free_seats(self, free_seats, flight): + flight.free_seats = free_seats + + @TextSyntax("Book seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def book_seat_for(self, first_name, last_name, flight_name): + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get(flight_name) + return self.service.book_seat(passenger, flight) + + @TextSyntax("Cancel seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def cancel_seat_for(self, first_name, last_name, flight_name): + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get("{0}".format(flight_name)) + return self.service.cancel_seat(passenger, flight) + + @TextSyntax(["Assume a valid ticket is issued", "Assume cancellation successful"], types=["OperationStatus"]) + def assume_valid_ticket(self, status): + self.test_case.assertTrue(status.valid, msg=status.msg) + + + @TextSyntax("Assume no valid ticket is issued", types=["OperationStatus"]) + def assume_no_valid_ticked_is_issued(self, status): + self.test_case.assertFalse(status.valid, msg=status.msg) + + + @TextSyntax("Assume #1 has passenger #2", types=["Flight", "Passenger"]) + def assume_has_passenger(self, flight, passenger): + self.test_case.assertTrue(flight.has_passenger(passenger)) \ No newline at end of file diff --git a/.svn/pristine/d8/d816e38e1691bd0ecddab1c9e062e51513934d76.svn-base b/.svn/pristine/d8/d816e38e1691bd0ecddab1c9e062e51513934d76.svn-base new file mode 100644 index 0000000..5d63d3d --- /dev/null +++ b/.svn/pristine/d8/d816e38e1691bd0ecddab1c9e062e51513934d76.svn-base @@ -0,0 +1,60 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeatTwice(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/d9/d959df2075f8108ba5372980b6055561619bf9dd.svn-base b/.svn/pristine/d9/d959df2075f8108ba5372980b6055561619bf9dd.svn-base new file mode 100644 index 0000000..cab196a --- /dev/null +++ b/.svn/pristine/d9/d959df2075f8108ba5372980b6055561619bf9dd.svn-base @@ -0,0 +1,6 @@ +There needs to be a free seat for the passenger. +There should be at least 0 free seats to handle overbooking. +Each Passenger can only be booked once. + +// Optional rule: +//The Passenger needs to be at least 18 years old. diff --git a/.svn/pristine/da/da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-base b/.svn/pristine/da/da39a3ee5e6b4b0d3255bfef95601890afd80709.svn-base new file mode 100644 index 0000000..e69de29 diff --git a/.svn/pristine/e1/e13d580b976ccf399031d175149c378cb50f4164.svn-base b/.svn/pristine/e1/e13d580b976ccf399031d175149c378cb50f4164.svn-base new file mode 100644 index 0000000..466919d --- /dev/null +++ b/.svn/pristine/e1/e13d580b976ccf399031d175149c378cb50f4164.svn-base @@ -0,0 +1,51 @@ +from persistence import entities +class InMemoryPersistenceContext(object): + __instance = None + + class __impl(object): + def __init__(self): + self.flights = {} + self.airplanes = {} + self.passengers = {} + + def update(self, entity): + update_dict = {entity.id: entity} + if isinstance(entity, entities.Flight): + self.flights.update(update_dict) + return + if isinstance(entity, entities.AirplaneType): + self.airplanes.update(update_dict) + return + if isinstance(entity, entities.Passenger): + self.passengers.update(update_dict) + return + + def create_flight(self, name): + flight = entities.Flight(name) + self.update(flight) + return flight + + def create_passenger(self, first_name, last_name): + passenger = entities.Passenger(first_name, last_name) + self.update(passenger) + return passenger + + def create_airplane_type(self, name): + airplane_type = entities.AirplaneType(name) + self.update(airplane_type) + return airplane_type + + + + def __init__(self): + if InMemoryPersistenceContext.__instance is None: + InMemoryPersistenceContext.__instance = InMemoryPersistenceContext.__impl() + self.__dict__['_InMemoryPersistenceContext__instance'] = InMemoryPersistenceContext.__instance + + def __getattr__(self, attr): + """ Delegate access to implementation """ + return getattr(self.__instance, attr) + + def __setattr__(self, attr, value): + """ Delegate access to implementation """ + return setattr(self.__instance, attr, value) \ No newline at end of file diff --git a/.svn/pristine/e4/e4a62745b544897db3e84e7732e9e371dc2fa230.svn-base b/.svn/pristine/e4/e4a62745b544897db3e84e7732e9e371dc2fa230.svn-base new file mode 100644 index 0000000..cf507d2 --- /dev/null +++ b/.svn/pristine/e4/e4a62745b544897db3e84e7732e9e371dc2fa230.svn-base @@ -0,0 +1,48 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeat(unittest.TestCase): + def __init__(self): + self.service = AirlineService() + self.test_support = TestSupport(self.service, self.persistence_context, self) + self.persistence_context = InMemoryPersistenceContext() + + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_787) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/e8/e86d9310f97e1b3fdd5b521ae7ad7abc3102456f.svn-base b/.svn/pristine/e8/e86d9310f97e1b3fdd5b521ae7ad7abc3102456f.svn-base new file mode 100644 index 0000000..fe9255c --- /dev/null +++ b/.svn/pristine/e8/e86d9310f97e1b3fdd5b521ae7ad7abc3102456f.svn-base @@ -0,0 +1,32 @@ +from service.validation.support import ValidationSupport + +class Rules(object): + """This class serves as a template for validation rule classes that are written + in plain natural language. The template is instantiated by NatSpec for all + the .natspec files in this package. The @MethodBody placeholder + in validate() is replaced with the code that performs the actual validation. + See class Rules for a concrete example validation class. + This class is an example of applying NatSpec for non-testing purposes. + """ + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """Checks that all validation rules are met. + :returns: the status of the validation (i.e., success or failure). + """ + """ + The code in this method is generated from: /de.devboost.natspec.example.python/service/validation/rules.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # There needs to be a free seat for the passenger. + self.validation_support.check_free_seats() + + # There should be at least 0 free seats to handle overbooking. + self.validation_support.check_free_seats_with_buffer(0) + + # Each Passenger can only be booked once. + self.validation_support.check_unique_passenger() + + + return self.validation_support.status \ No newline at end of file diff --git a/.svn/pristine/ef/ef1bedbc0450b71269db733433eccc98d58ba917.svn-base b/.svn/pristine/ef/ef1bedbc0450b71269db733433eccc98d58ba917.svn-base new file mode 100644 index 0000000..9bc04bc --- /dev/null +++ b/.svn/pristine/ef/ef1bedbc0450b71269db733433eccc98d58ba917.svn-base @@ -0,0 +1,75 @@ +from persistence import entities +class InMemoryPersistenceContext(object): + """The InMemoryPersistenceContext is a very basic store for entity + objects. It basically holds all objects in memory. In a real application, + this will probably be replaced by a Data Access Object (DAO) that retrieves + object from and stores objects to a database.""" + + # This fields holds the single instance of this class. + __instance = None + + class __impl(object): + def __init__(self): + self.flights = {} + self.airplanes = {} + self.passengers = {} + + def update(self, entity): + """Stores the given entity. + :param entity: the entity to store + """ + update_dict = {entity.id: entity} + if isinstance(entity, entities.Flight): + self.flights.update(update_dict) + return + if isinstance(entity, entities.AirplaneType): + self.airplanes.update(update_dict) + return + if isinstance(entity, entities.Passenger): + self.passengers.update(update_dict) + return + + def create_flight(self, name): + """Creates a new flight with the given name. + :param name: the name of the flight. + :returns: the created object + """ + flight = entities.Flight(name) + self.update(flight) + return flight + + def create_passenger(self, first_name, last_name): + """Creates a new passenger with the given first and last name. + :param first_name: the first name of the passenger. + :param last_name: the name of the passenger. + :returns: the created object + """ + passenger = entities.Passenger(first_name, last_name) + self.update(passenger) + return passenger + + + def create_airplane_type(self, name): + """Creates a new type of airplane with the given name. + :param name: the name of the airplane type. + :returns: the created object. + """ + airplane_type = entities.AirplaneType(name) + self.update(airplane_type) + return airplane_type + + + def __init__(self): + """Creates the one and only instance of this class.""" + + if InMemoryPersistenceContext.__instance is None: + InMemoryPersistenceContext.__instance = InMemoryPersistenceContext.__impl() + self.__dict__['_InMemoryPersistenceContext__instance'] = InMemoryPersistenceContext.__instance + + def __getattr__(self, attr): + """Delegate access to implementation""" + return getattr(self.__instance, attr) + + def __setattr__(self, attr, value): + """Delegate access to implementation""" + return setattr(self.__instance, attr, value) diff --git a/.svn/pristine/f6/f6273168fee1f361737a1e0ab4ba8f6c73eae2ee.svn-base b/.svn/pristine/f6/f6273168fee1f361737a1e0ab4ba8f6c73eae2ee.svn-base new file mode 100644 index 0000000..2cc5335 --- /dev/null +++ b/.svn/pristine/f6/f6273168fee1f361737a1e0ab4ba8f6c73eae2ee.svn-base @@ -0,0 +1,43 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeat(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234"), airplaneType_Boeing_787) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/f8/f875d0cbf0db56b5878ce800672c9b8efb6e7f90.svn-base b/.svn/pristine/f8/f875d0cbf0db56b5878ce800672c9b8efb6e7f90.svn-base new file mode 100644 index 0000000..296dc38 --- /dev/null +++ b/.svn/pristine/f8/f875d0cbf0db56b5878ce800672c9b8efb6e7f90.svn-base @@ -0,0 +1,66 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelSeatTwice(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12341 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12341) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/pristine/ff/ff899aefbb51e54d5916877a0b5f3bd22470825e.svn-base b/.svn/pristine/ff/ff899aefbb51e54d5916877a0b5f3bd22470825e.svn-base new file mode 100644 index 0000000..bf66e34 --- /dev/null +++ b/.svn/pristine/ff/ff899aefbb51e54d5916877a0b5f3bd22470825e.svn-base @@ -0,0 +1,20 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelSeatTwice(unittest.TestCase): + def setUp(self): + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.svn/wc.db b/.svn/wc.db new file mode 100644 index 0000000..fbcf3bb Binary files /dev/null and b/.svn/wc.db differ diff --git a/persistence/__init__.py b/persistence/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/persistence/entities.py b/persistence/entities.py new file mode 100644 index 0000000..e2e2116 --- /dev/null +++ b/persistence/entities.py @@ -0,0 +1,90 @@ +class Entity(object): + # A global counter that holds the next available entity ID. + _counter = 0 + + def __init__(self): + """Creates a new entity and initialized its ID.""" + Entity._counter += 1 + self.id = Entity._counter + + +class NamedEntity(Entity): + """This is a super class for all entities that carry a name.""" + def __init__(self, name): + super(NamedEntity, self).__init__() + self.name = name + + +class Passenger(Entity): + """A Passenger object represents a person who can be booked on flights.""" + + def __init__(self, first_name, last_name): + """Creates a new passenger with the given first and last name, having an initial ago of zero. + :param firstname: the first name of the passenger. + :param lastname: the last name of the passenger. + """ + super(Passenger, self).__init__() + self.first_name = first_name + self.last_name = last_name + self.age = 0 + +class Flight(NamedEntity): + """A Flight represents the opportunity to travel from one airport to another. + Each Flight is executed using a particular type of airplane and holds a limited amount of passengers. + """ + + def __init__(self, name): + """Creates a new flight with the given name. + :param name: the new name for the flight. + """ + super(Flight, self).__init__(name) + self.__airplane = None + self.passenger_ids = [] + self.__free_seats = 0 + + @property + def airplane(self): + return self._airplane + + @airplane.setter + def airplane(self, value): + self.__airplane = value + self.__free_seats = value.total_seats + + @property + def free_seats(self): + return self.__free_seats - len(self.passenger_ids) + + @free_seats.setter + def free_seats(self, value): + self.__free_seats = value + + def has_passenger(self, passenger): + return passenger.id in self.passenger_ids + + def add_passenger(self, passenger): + self.passenger_ids.append(passenger.id) + + def remove_passenger(self, passenger): + if passenger.id in self.passenger_ids: + self.passenger_ids.remove(passenger.id) + return True + return False + + +class AirplaneType(NamedEntity): + """An AirplaneType represents a specific typo of airplane which is + characterized by its name and a number of total seats. + """ + + def __init__(self, name): + """Creates a new AirplaneType entity with the given name. + :param name: the name of the type of airplane. + """ + super(AirplaneType, self).__init__(name) + self.total_seats = 0 + + + + + diff --git a/persistence/in_memory_context.py b/persistence/in_memory_context.py new file mode 100644 index 0000000..9bc04bc --- /dev/null +++ b/persistence/in_memory_context.py @@ -0,0 +1,75 @@ +from persistence import entities +class InMemoryPersistenceContext(object): + """The InMemoryPersistenceContext is a very basic store for entity + objects. It basically holds all objects in memory. In a real application, + this will probably be replaced by a Data Access Object (DAO) that retrieves + object from and stores objects to a database.""" + + # This fields holds the single instance of this class. + __instance = None + + class __impl(object): + def __init__(self): + self.flights = {} + self.airplanes = {} + self.passengers = {} + + def update(self, entity): + """Stores the given entity. + :param entity: the entity to store + """ + update_dict = {entity.id: entity} + if isinstance(entity, entities.Flight): + self.flights.update(update_dict) + return + if isinstance(entity, entities.AirplaneType): + self.airplanes.update(update_dict) + return + if isinstance(entity, entities.Passenger): + self.passengers.update(update_dict) + return + + def create_flight(self, name): + """Creates a new flight with the given name. + :param name: the name of the flight. + :returns: the created object + """ + flight = entities.Flight(name) + self.update(flight) + return flight + + def create_passenger(self, first_name, last_name): + """Creates a new passenger with the given first and last name. + :param first_name: the first name of the passenger. + :param last_name: the name of the passenger. + :returns: the created object + """ + passenger = entities.Passenger(first_name, last_name) + self.update(passenger) + return passenger + + + def create_airplane_type(self, name): + """Creates a new type of airplane with the given name. + :param name: the name of the airplane type. + :returns: the created object. + """ + airplane_type = entities.AirplaneType(name) + self.update(airplane_type) + return airplane_type + + + def __init__(self): + """Creates the one and only instance of this class.""" + + if InMemoryPersistenceContext.__instance is None: + InMemoryPersistenceContext.__instance = InMemoryPersistenceContext.__impl() + self.__dict__['_InMemoryPersistenceContext__instance'] = InMemoryPersistenceContext.__instance + + def __getattr__(self, attr): + """Delegate access to implementation""" + return getattr(self.__instance, attr) + + def __setattr__(self, attr, value): + """Delegate access to implementation""" + return setattr(self.__instance, attr, value) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b561c84 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +natspec_utils diff --git a/service/__init__.py b/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/airline_service.py b/service/airline_service.py new file mode 100644 index 0000000..578cbcd --- /dev/null +++ b/service/airline_service.py @@ -0,0 +1,36 @@ +from service.validation.rules import Rules +from service.status import OperationStatus + +class AirlineService(object): + """The AirlineService provides very basic business functionality for the + airline domain. It allows to book seats for passengers on flights + and to cancel these seats. + """ + + def book_seat(self, passenger, flight): + """Tries to book a seat for the given passenger on the given flight. Before + the seat is actually booked some validation rules are checked to make + sure the constraints of the domain (e.g., that a passenger can book at + most one seat for a flight) are met. If one of the validation rules is + violated, this operation fails. + :param flight: the flight to book the seat on. + :param passenger: the passenger to book the seat for. + :returns: a status object representing the operations success (or failure). + """ + rules = Rules(flight, passenger) + status = rules.validate() + if status.valid: + flight.add_passenger(passenger) + return status + + def cancel_seat(self, passenger, flight): + """Cancels the seat booked by the given passenger on the given flight. This + operation can fail if the passenger has not booked a seat on the given + flight. + :param passenger: the passenger to cancel the seat for. + :param flight: the flight to cancel the seat on. + :returns: a status object representing the operations success (or failure). + """ + if flight.remove_passenger(passenger): + return OperationStatus("Passenger was removed", True) + return OperationStatus("Passenger was not booked on flight", False) \ No newline at end of file diff --git a/service/status.py b/service/status.py new file mode 100644 index 0000000..94a56ba --- /dev/null +++ b/service/status.py @@ -0,0 +1,9 @@ +class OperationStatus(object): + """Objects of type OperationStatus are used to capture the result of + business operations. Each result comprises of a message and a validity flag + which indicates success or failure of the operation. + """ + + def __init__(self, msg="", status=True): + self.msg = msg + self.valid = status \ No newline at end of file diff --git a/service/validation/_NatSpecTemplate.py b/service/validation/_NatSpecTemplate.py new file mode 100644 index 0000000..3b42876 --- /dev/null +++ b/service/validation/_NatSpecTemplate.py @@ -0,0 +1,19 @@ +from service.validation.support import ValidationSupport + +class _NatSpecTemplate(object): + """This class serves as a template for validation rule classes that are written + in plain natural language. The template is instantiated by NatSpec for all + the .natspec files in this package. The @MethodBody placeholder + in validate() is replaced with the code that performs the actual validation. + See class Rules for a concrete example validation class. + This class is an example of applying NatSpec for non-testing purposes. + """ + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """Checks that all validation rules are met. + :returns: the status of the validation (i.e., success or failure). + """ + """ @MethodBody """ + return self.validation_support.status \ No newline at end of file diff --git a/service/validation/__init__.py b/service/validation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/validation/rules.natspec b/service/validation/rules.natspec new file mode 100644 index 0000000..cab196a --- /dev/null +++ b/service/validation/rules.natspec @@ -0,0 +1,6 @@ +There needs to be a free seat for the passenger. +There should be at least 0 free seats to handle overbooking. +Each Passenger can only be booked once. + +// Optional rule: +//The Passenger needs to be at least 18 years old. diff --git a/service/validation/rules.py b/service/validation/rules.py new file mode 100644 index 0000000..fe9255c --- /dev/null +++ b/service/validation/rules.py @@ -0,0 +1,32 @@ +from service.validation.support import ValidationSupport + +class Rules(object): + """This class serves as a template for validation rule classes that are written + in plain natural language. The template is instantiated by NatSpec for all + the .natspec files in this package. The @MethodBody placeholder + in validate() is replaced with the code that performs the actual validation. + See class Rules for a concrete example validation class. + This class is an example of applying NatSpec for non-testing purposes. + """ + def __init__(self, flight, passenger): + self.validation_support = ValidationSupport(flight, passenger) + + def validate(self): + """Checks that all validation rules are met. + :returns: the status of the validation (i.e., success or failure). + """ + """ + The code in this method is generated from: /de.devboost.natspec.example.python/service/validation/rules.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # There needs to be a free seat for the passenger. + self.validation_support.check_free_seats() + + # There should be at least 0 free seats to handle overbooking. + self.validation_support.check_free_seats_with_buffer(0) + + # Each Passenger can only be booked once. + self.validation_support.check_unique_passenger() + + + return self.validation_support.status \ No newline at end of file diff --git a/service/validation/support.py b/service/validation/support.py new file mode 100644 index 0000000..4f359fd --- /dev/null +++ b/service/validation/support.py @@ -0,0 +1,50 @@ +from service.status import OperationStatus +from natspec_utils.decorators import TextSyntax +class ValidationSupport(): + """The ValidationSupport call defined all methods that are required to + execute the textual validation rules present in this example. + """ + + def __init__(self, flight, passenger): + """Creates a new instance of this class that can be used to validate the + given flight and passenger. + + :param flight: the flight to validate. + :param passenger: the passenger to validate. + """ + self.flight = flight + self.passenger = passenger + self.status = OperationStatus() + + def set_invalid(self, msg): + """Sets the status of this validation to invalid (failure) and adds the given message. + :param msg: the message to add. + """ + self.status.valid = False + self.status.msg = msg + + @TextSyntax("Each Passenger can only be booked once.") + def check_unique_passenger(self): + """Checks that the passenger has not already booked a seat on this flight.""" + if self.passenger.id in self.flight.passenger_ids: + self.set_invalid("A passenger can only be booked once for each flight.") + + @TextSyntax("There should be at least #1 free seats to handle overbooking.", types=["int"]) + def check_free_seats_with_buffer(self, overbooking_buffer): + """Checks that the given number of seats is held free.""" + if self.flight.free_seats < overbooking_buffer: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("There needs to be a free seat for the passenger.") + def check_free_seats(self): + """Checks that there is at least one seat available.""" + if self.flight.free_seats < 1: + self.set_invalid("There are no free seats for the flight.") + + @TextSyntax("The Passenger needs to be at least #1 years old.", types=["int"]) + def passenger_needs_to_be_at_least_years_old(self, minimal_age): + """Checks that the passenger has at least the given age (in years).""" + if self.passenger.age < minimal_age: + self.set_invalid("The passenger needs to be at least {0} years.".format(minimal_age)) + + diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/scenarios/_NatSpecTemplate.py b/test/scenarios/_NatSpecTemplate.py new file mode 100644 index 0000000..06940f6 --- /dev/null +++ b/test/scenarios/_NatSpecTemplate.py @@ -0,0 +1,27 @@ +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class _NatSpecTemplate(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ @MethodBody """ + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scenarios/__init__.py b/test/scenarios/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/scenarios/book_seat.natspec b/test/scenarios/book_seat.natspec new file mode 100644 index 0000000..ba848a1 --- /dev/null +++ b/test/scenarios/book_seat.natspec @@ -0,0 +1,13 @@ +// This scenario describes a simple booking process +// for an exemplary passenger + +Given a Passenger John Doe +Given an Airplane Boeing-787 + +Given a flight LH-1234 + that is executed using a Boeing-787 + With 200 free seats + +Book seat for John Doe at LH-1234 + +Assume a valid ticket is issued \ No newline at end of file diff --git a/test/scenarios/book_seat.py b/test/scenarios/book_seat.py new file mode 100644 index 0000000..60010c6 --- /dev/null +++ b/test/scenarios/book_seat.py @@ -0,0 +1,54 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeat(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scenarios/book_seat_twice.natspec b/test/scenarios/book_seat_twice.natspec new file mode 100644 index 0000000..2478004 --- /dev/null +++ b/test/scenarios/book_seat_twice.natspec @@ -0,0 +1,15 @@ +// This scenario describes an erroneous booking example +// where the same passenger is booked twice for one flight + +Given a Passenger John Doe +Given an Airplane Boeing-787 +Given a flight LH-1234 + that is executed using a Boeing-787 + With 200 free seats + +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// Second booking for the same passenger should fail +Book seat for John Doe at LH-1234 + Assume no valid ticket is issued \ No newline at end of file diff --git a/test/scenarios/book_seat_twice.py b/test/scenarios/book_seat_twice.py new file mode 100644 index 0000000..5d63d3d --- /dev/null +++ b/test/scenarios/book_seat_twice.py @@ -0,0 +1,60 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class BookSeatTwice(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/book_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given a Passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given an Airplane Boeing-787 + airplaneType_Boeing_787 = self.test_support.given_an_airplane(u("Boeing-787")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-787 + self.test_support.that_is_executed_using_a(u("Boeing-787"), flight_LH_1234) + + # With 200 free seats + self.test_support.with_free_seats(200, flight_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scenarios/cancel_and_rebook_seat.natspec b/test/scenarios/cancel_and_rebook_seat.natspec new file mode 100644 index 0000000..281acfc --- /dev/null +++ b/test/scenarios/cancel_and_rebook_seat.natspec @@ -0,0 +1,24 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + With 1 free seats + +Given a passenger John Doe +Given a passenger Jane Mejer + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// second passenger +Book seat for Jane Mejer at LH-1234 + Assume no valid ticket is issued + +// cancel first passenger +Cancel seat for John Doe at LH-1234 + Assume cancellation successful + +// rebook second passenger on now free set +Book seat for Jane Mejer at LH-1234 + Assume a valid ticket is issued diff --git a/test/scenarios/cancel_and_rebook_seat.py b/test/scenarios/cancel_and_rebook_seat.py new file mode 100644 index 0000000..df16336 --- /dev/null +++ b/test/scenarios/cancel_and_rebook_seat.py @@ -0,0 +1,75 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelAndRebookSeat(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_and_rebook_seat.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 1 free seats + self.test_support.with_free_seats(1, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Given a passenger Jane Mejer + passenger_Jane_Mejer = self.test_support.given_a_passenger(u("Jane"), u("Mejer")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jane_Mejer_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume cancellation successful + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Book seat for Jane Mejer at LH-1234 + operationStatus_Jane_Mejer_LH_12340 = self.test_support.book_seat_for(u("Jane"), u("Mejer"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Mejer_LH_12340) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scenarios/cancel_seat_twice.natspec b/test/scenarios/cancel_seat_twice.natspec new file mode 100644 index 0000000..10705ba --- /dev/null +++ b/test/scenarios/cancel_seat_twice.natspec @@ -0,0 +1,18 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + With 2 free seats + +Given a passenger John Doe + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// cancel first passenger +Cancel seat for John Doe at LH-1234 + Assume a valid ticket is issued + +Cancel seat for John Doe at LH-1234 + Assume no valid ticket is issued diff --git a/test/scenarios/cancel_seat_twice.py b/test/scenarios/cancel_seat_twice.py new file mode 100644 index 0000000..296dc38 --- /dev/null +++ b/test/scenarios/cancel_seat_twice.py @@ -0,0 +1,66 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class CancelSeatTwice(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/cancel_seat_twice.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # With 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12340 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_12340) + + # Cancel seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_12341 = self.test_support.cancel_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_John_Doe_LH_12341) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/scenarios/overbook_seat_number.natspec b/test/scenarios/overbook_seat_number.natspec new file mode 100644 index 0000000..3709f1c --- /dev/null +++ b/test/scenarios/overbook_seat_number.natspec @@ -0,0 +1,21 @@ +Given an airplane Boeing-737-600 + +Given a flight LH-1234 + that is executed using a Boeing-737-600 + with 2 free seats + +Given a passenger John Doe + +// first passenger +Book seat for John Doe at LH-1234 + Assume a valid ticket is issued + +// second passenger +Given a passenger Jane Doe + Book seat for Jane Doe at LH-1234 + Assume a valid ticket is issued + +// third passenger +Given a passenger Jim Doe + Book seat for Jim Doe at LH-1234 + Assume no valid ticket is issued \ No newline at end of file diff --git a/test/scenarios/overbook_seat_number.py b/test/scenarios/overbook_seat_number.py new file mode 100644 index 0000000..95d1b9b --- /dev/null +++ b/test/scenarios/overbook_seat_number.py @@ -0,0 +1,72 @@ +from natspec_utils.stringutils import stringToUnicode as u; + +import unittest +from test.support import TestSupport +from service.airline_service import AirlineService +from persistence.in_memory_context import InMemoryPersistenceContext + +class OverbookSeatNumber(unittest.TestCase): + """This class serves as a template for all classes that are generated for + NatSpec scenarios (.natspec files). It is recognized by NatSpec based on its + special name and applies to all scenarios in the same package and all sub + packages (unless there is another template class in one of the sub packages). + This particular template is a unittest test case where the concrete steps of the + test are filled by the NatSpec code generator. + """ + + def setUp(self): + """Sets up the test environment (i.e., initialize the service class, the + entity manager and the test support class). + """ + self.service = AirlineService() + self.persistence_context = InMemoryPersistenceContext() + self.test_support = TestSupport(self.service, self.persistence_context, self) + + def test(self): + """ + The code in this method is generated from: /de.devboost.natspec.example.python/test/scenarios/overbook_seat_number.natspec + Never change this method or any contents of this file, all local changes will we overwritten. + """ + # Given an airplane Boeing-737-600 + airplaneType_Boeing_737_600 = self.test_support.given_an_airplane(u("Boeing-737-600")) + + # Given a flight LH-1234 + flight_LH_1234 = self.test_support.given_a_flight(u("LH-1234")) + + # that is executed using a Boeing-737-600 + self.test_support.that_is_executed_using_a(u("Boeing-737-600"), flight_LH_1234) + + # with 2 free seats + self.test_support.with_free_seats(2, flight_LH_1234) + + # Given a passenger John Doe + passenger_John_Doe = self.test_support.given_a_passenger(u("John"), u("Doe")) + + # Book seat for John Doe at LH-1234 + operationStatus_John_Doe_LH_1234 = self.test_support.book_seat_for(u("John"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_John_Doe_LH_1234) + + # Given a passenger Jane Doe + passenger_Jane_Doe = self.test_support.given_a_passenger(u("Jane"), u("Doe")) + + # Book seat for Jane Doe at LH-1234 + operationStatus_Jane_Doe_LH_1234 = self.test_support.book_seat_for(u("Jane"), u("Doe"), u("LH-1234")) + + # Assume a valid ticket is issued + self.test_support.assume_valid_ticket(operationStatus_Jane_Doe_LH_1234) + + # Given a passenger Jim Doe + passenger_Jim_Doe = self.test_support.given_a_passenger(u("Jim"), u("Doe")) + + # Book seat for Jim Doe at LH-1234 + operationStatus_Jim_Doe_LH_1234 = self.test_support.book_seat_for(u("Jim"), u("Doe"), u("LH-1234")) + + # Assume no valid ticket is issued + self.test_support.assume_no_valid_ticked_is_issued(operationStatus_Jim_Doe_LH_1234) + + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/test/support.py b/test/support.py new file mode 100644 index 0000000..3aaad00 --- /dev/null +++ b/test/support.py @@ -0,0 +1,141 @@ +from natspec_utils.decorators import TextSyntax + + +class TestSupport(object): + """This class contains all test support methods that are required to make the + example specifications executable. Methods that are decorated with the + TextSyntax decorator are recognized by NatSpec. + This class is parameterized by two parameters that are passed to the + constructor (the service class which implements the business logic and the + entity manager that provides access to all entities). + """ + + def __init__(self, service, persistence_context, test_case): + """Creates a new {@link TestSupport} instance. This constructor is usually + invoked from a {@link _NatSpecTemplate}. + :param service: the business service logic. + :param persistence_context: the entity manager to access entities. + :param test_case: the test case we are running, needed to access asserts + """ + self.service = service + self.persistence_context = persistence_context + self.test_case = test_case + self.passengers = {} + self.flights = {} + self.airplane_types = {} + + @TextSyntax(["Given a Passenger #1 #2"], types=["str", "str"], return_type="Passenger") + def given_a_passenger(self, first_name, last_name): + """Creates a new passenger. + :param first_name: the first name of the passenger. + :param last_name: the last name of the passenger. + :returns: the newly created passenger. + """ + passenger = self.persistence_context.create_passenger(first_name, last_name) + self.passengers.update({"{0} {1}".format(first_name, last_name): passenger}) + return passenger + + @TextSyntax("With age of #2 years", types=["Passenger", "int"]) + def with_age_of_years(self, passenger, age): + """Sets the age of the given passenger. The passenger is expected to be + contained in the implicit context (i.e., it must be created by a previous + sentence/test support method). The name of the passenger is not + explicitly required here, because there is no placeholder for the + passenger parameter (i.e., #1 is missing). + :param passenger: the passenger to set the age for. + :param age: the new age for the passenger. + """ + passenger.age = age + + @TextSyntax(["Given an Airplane #1"], types=["str"], return_type="AirplaneType") + def given_an_airplane(self, name): + """Creates a new type of airplane. + :param name: the name of the type of airplane. + :returns: the newly created airplane type. + """ + airplane_type = self.persistence_context.create_airplane_type(name) + self.airplane_types.update({name: airplane_type}) + return airplane_type + + @TextSyntax(["Given a flight #1"], types=["str", ], return_type="Flight") + def given_a_flight(self, name): + """Creates a new flight. + :param name: the name of the flight. + :returns: the newly created flight. + """ + flight = self.persistence_context.create_flight(name) + self.flights.update({name: flight}) + return flight + + @TextSyntax("that is executed using a #1", types=["str", "Flight"]) + def that_is_executed_using_a(self, airplane_name, flight): + """Assigns the type of airplane that is used to execute the last mentioned flight. + :param airplane_name: the type of airplane to assign to the flight. + :param flight: the flight for which to set the airplane type (must be available from context). + """ + airplane = self.airplane_types.get(airplane_name) + flight.airplane = airplane + + @TextSyntax("With #1 free seats", types=["int", "Flight"]) + def with_free_seats(self, free_seats, flight): + """Sets the number of free seats for the flight mentioned last. + :param free_seats: the number of free seats + :param flight: the flight to set the seats for (must be available from context). + """ + flight.free_seats = free_seats + + @TextSyntax("Book seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def book_seat_for(self, first_name, last_name, flight_name): + """Tries to book a seat for the given passenger on the given flight. + :param first_name: the first name of passenger to book the flight for + :param last_name: the last name of passenger to book the flight for + :param flight_name: the name of flight to book the seat on. + :returns: the status of the booking operation which can be validated using + assume_valid_ticket(OperationStatus) or + assume_no_valid_ticked_is_issued(OperationStatus). + """ + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get(flight_name) + return self.service.book_seat(passenger, flight) + + @TextSyntax("Cancel seat for #1 #2 at #3", types=["str", "str", "str"], return_type="OperationStatus") + def cancel_seat_for(self, first_name, last_name, flight_name): + """Tries to cancel the given passenger on the given flight. + :param first_name: the first name of passenger to book the flight for + :param last_name: the last name of passenger to book the flight for + :param flight_name: the name of flight to book the seat on. + :returns: the status of the cancel operation which can be validated using + assume_valid_ticket(OperationStatus) or + assume_no_valid_ticked_is_issued(OperationStatus). + """ + passenger = self.passengers.get("{0} {1}".format(first_name, last_name)) + flight = self.flights.get("{0}".format(flight_name)) + return self.service.cancel_seat(passenger, flight) + + @TextSyntax(["Assume a valid ticket is issued", "Assume cancellation successful"], types=["OperationStatus"]) + def assume_valid_ticket(self, status): + """Checks that the validity of the last operation is True + (i.e., that the operation was successful). This method has a TextSyntax decorator + with multiple patterns (first arg) to map multiple sentences to this method. + :param status: the status of the last operation (must be implicitly available from context). + """ + self.test_case.assertTrue(status.valid, msg=status.msg) + + @TextSyntax("Assume no valid ticket is issued", types=["OperationStatus"]) + def assume_no_valid_ticked_is_issued(self, status): + """Checks that the validity of the last executed business operations is False. + :param status: the status of the last operation (implicit parameter, not explicitly mentioned in sentence) + """ + self.test_case.assertFalse(status.valid, msg=status.msg) + + + @TextSyntax("Assume #1 has passenger #2", types=["Flight", "Passenger"]) + def assume_has_passenger(self, flight, passenger): + """Checks that the given passenger is booked for the given flight. Both the + flight and the passenger must be referenced explicitly. + :param flight: the flight to check + :param passenger: the passenger to check + """ + self.test_case.assertTrue(flight.has_passenger(passenger)) + +