diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4c209dde8f..d224c9f3b6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,24 +1,24 @@ # Your name -Please write your full name here to make it easier to find your pull request. +Coral Baker # User stories Please list which user stories you've implemented (delete the ones that don't apply). -- [ ] User story 1: "I want to instruct a plane to land at an airport" -- [ ] User story 2: "I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport" -- [ ] User story 3: "I want to prevent landing when the airport is full" -- [ ] User story 4: "I would like a default airport capacity that can be overridden as appropriate" -- [ ] User story 5: "I want to prevent takeoff when weather is stormy" -- [ ] User story 6: "I want to prevent landing when weather is stormy" +- [X] User story 1: "I want to instruct a plane to land at an airport" +- [X] User story 2: "I want to instruct a plane to take off from an airport and confirm that it is no longer in the airport" +- [X] User story 3: "I want to prevent landing when the airport is full" +- [X] User story 4: "I would like a default airport capacity that can be overridden as appropriate" +- [X] User story 5: "I want to prevent takeoff when weather is stormy" +- [X] User story 6: "I want to prevent landing when weather is stormy" # README checklist Does your README contains instructions for -- [ ] how to install, -- [ ] how to run, -- [ ] and how to test your code? +- [X] how to install, +- [X] how to run, +- [X] and how to test your code? [Here is a pill](https://github.com/makersacademy/course/blob/main/pills/readmes.md) that can help you write a great README! \ No newline at end of file diff --git a/README.md b/README.md index 6dd4fa6bc9..120e78ee38 100644 --- a/README.md +++ b/README.md @@ -13,26 +13,47 @@ Airport Challenge ``` -Instructions ---------- +This program will control the flow of planes at an airport: +- Land and store a plane in an airport if the hangar is not full. +- Allow a plane to take off from the airport, as long as there are planes in the hangar. +- Check if a plane has departed. +- Change the default capacity of the hangar if required. +- Prevent takeoff and landing if weather is stormy. + +Installation +----- + +1. Fork this repository. +2. Clone your new forked repository using `git clone` followed by your fork URL. +3. Move into the repository by using `cd airport_challenge`. +4. Run the command `gem install bundler` (if you don't have bundler already). +5. When the installation completes, run `bundle`. + + +Program Usage +----- + +Use irb to run the program from the main repository: + +```zsh +irb -r './lib/airport.rb' +``` + -* Feel free to use google, your notes, books, etc. but work on your own -* If you refer to the solution of another coach or student, please put a link to that in your README -* If you have a partial solution, **still check in a partial solution** -* You must submit a pull request to this repo with your code by 10am Monday morning +Test Usage +----- -Steps -------- +Use rspec to run the tests from the main repository: -1. Fork this repo, and clone to your local machine -2. Run the command `gem install bundler` (if you don't have bundler already) -3. When the installation completes, run `bundle` -4. Complete the following task: +```zsh +rspec +``` -Task + +User Stories ----- -We have a request from a client to write the software to control the flow of planes at an airport. The planes can land and take off provided that the weather is sunny. Occasionally it may be stormy, in which case no planes can land or take off. Here are the user stories that we worked out in collaboration with the client: +The client requests are broken down as follows: ``` As an air traffic controller @@ -45,45 +66,17 @@ I want to instruct a plane to take off from an airport and confirm that it is no As an air traffic controller To ensure safety -I want to prevent landing when the airport is full +I want to prevent landing when the airport is full As the system designer So that the software can be used for many different airports I would like a default airport capacity that can be overridden as appropriate -As an air traffic controller +As an air traffic controller To ensure safety I want to prevent takeoff when weather is stormy As an air traffic controller To ensure safety I want to prevent landing when weather is stormy -``` - -Your task is to test drive the creation of a set of classes/modules to satisfy all the above user stories. You will need to use a random number generator to set the weather (it is normally sunny but on rare occasions it may be stormy). In your tests, you'll need to use a stub to override random weather to ensure consistent test behaviour. - -Your code should defend against [edge cases](http://programmers.stackexchange.com/questions/125587/what-are-the-difference-between-an-edge-case-a-corner-case-a-base-case-and-a-b) such as inconsistent states of the system ensuring that planes can only take off from airports they are in; planes that are already flying cannot take off and/or be in an airport; planes that are landed cannot land again and must be in an airport, etc. - -For overriding random weather behaviour, please read the documentation to learn how to use test doubles: https://www.relishapp.com/rspec/rspec-mocks/docs . There’s an example of using a test double to test a die that’s relevant to testing random weather in the test. - -Please create separate files for every class, module and test suite. - -In code review we'll be hoping to see: - -* All tests passing -* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good) -* The code is elegant: every class has a clear responsibility, methods are short etc. - -Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment. - -**BONUS** - -* Write an RSpec **feature** test that lands and takes off a number of planes - -Note that is a practice 'tech test' of the kinds that employers use to screen developer applicants. More detailed submission requirements/guidelines are in [CONTRIBUTING.md](CONTRIBUTING.md) - -Finally, don’t overcomplicate things. This task isn’t as hard as it may seem at first. - -* **Submit a pull request early.** - -* Finally, please submit a pull request before Monday at 10am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 10am. +``` \ No newline at end of file diff --git a/lib/airport.rb b/lib/airport.rb new file mode 100644 index 0000000000..19d98fba1f --- /dev/null +++ b/lib/airport.rb @@ -0,0 +1,41 @@ +require_relative '../lib/plane.rb' +require_relative '../lib/weather.rb' + +class Airport + attr_reader :hangar, :capacity + DEFAULT_CAPACITY = 10 + + def initialize(capacity = DEFAULT_CAPACITY) + @hangar = [] + @capacity = capacity + @weather = Weather.new + end + + def land(plane) + land_checks(plane) + @hangar << plane + end + + def take_off(plane) + take_off_checks(plane) + @hangar.delete(plane) + end + + private + + def land_checks(plane) + fail 'Hangar full.' if @hangar.count >= @capacity + fail 'Plane already grounded.' if @hangar.include? plane + fail 'Weather stormy, landing not available.' if storm? == true + end + + def take_off_checks(plane) + fail 'No planes in hangar.' if @hangar.count == 0 + fail 'Plane not in hangar.' if !@hangar.include? plane + fail 'Weather stormy, take off not available.' if storm? == true + end + + def storm? + @weather.storm? + end +end diff --git a/lib/plane.rb b/lib/plane.rb new file mode 100644 index 0000000000..a2b24caeb1 --- /dev/null +++ b/lib/plane.rb @@ -0,0 +1,19 @@ +class Plane + attr_reader :flying + + def initialize + @flying = true + end + + def ground + @flying = false + end + + def air + @flying = true + end +end + +# Now that I've completed the 'stormy' stories and understand rspec a bit better, +# I might be able to use the above to detect whether a plane has landed or not. +# Unfortunately it's quite late and best saved for another time! \ No newline at end of file diff --git a/lib/weather.rb b/lib/weather.rb new file mode 100644 index 0000000000..7f0222881f --- /dev/null +++ b/lib/weather.rb @@ -0,0 +1,5 @@ +class Weather + def storm? + rand(1..6) == 6 + end +end \ No newline at end of file diff --git a/spec/airport_spec.rb b/spec/airport_spec.rb new file mode 100644 index 0000000000..68bce95cff --- /dev/null +++ b/spec/airport_spec.rb @@ -0,0 +1,97 @@ +require_relative '../lib/airport.rb' + +describe Airport do + let(:plane) { double :plane } + let(:plane2) { double :plane2 } + let(:airport) { Airport.new(5) } + + describe '#capacity' do + it 'should confirm default capacity is set to 10.' do + expect(subject.capacity).to eq Airport::DEFAULT_CAPACITY + end + + it 'should allow user to set the docking station capacity' do + allow(airport).to receive(:storm?).and_return false + 5.times { airport.land(be_an_instance_of plane) } + expect{ airport.land(plane) }.to raise_error 'Hangar full.' + end + end + + describe '#land' do + it { is_expected.to respond_to(:land).with(1).argument } + + it 'should store a plane in hangar when landed' do + allow(subject).to receive(:storm?).and_return false + expect(subject.land(plane)).not_to be_empty + end + + it 'raises an error when hangar is full.' do + allow(subject).to receive(:storm?).and_return false + Airport::DEFAULT_CAPACITY.times { subject.land(be_an_instance_of plane) } + expect { subject.land(plane) }.to raise_error 'Hangar full.' + end + + it 'should raise error if grounded plane tries landing again.' do + allow(subject).to receive(:storm?).and_return false + subject.land(plane) + expect { subject.land(plane) }.to raise_error 'Plane already grounded.' + end + + it 'raises error when plane tries to land during storm' do + allow(subject).to receive(:storm?).and_return true + expect { subject.land(plane) }.to raise_error 'Weather stormy, landing not available.' + end + + it 'should not raise an error for landing planes when weather clear' do + allow(subject).to receive(:storm?).and_return false + expect { subject.land(plane) }.to_not raise_error + end + + # Didn't get around to looking futher into this edge case + # it 'should raise error if grounded plane tries to land in different airport.' do + # subject.land(plane) + # expect { airport.land(plane) }.to raise_error 'Plane in another airport.' + # end + end + + describe '#take_off' do + it { is_expected.to respond_to(:take_off).with(1).argument } + + it 'should remove plane from airport' do + allow(subject).to receive(:storm?).and_return false + subject.land(plane) + expect(subject.take_off(plane)).to eq plane + end + + it 'should remove the plane requested from airport' do + allow(airport).to receive(:storm?).and_return false + airport.land(plane) + airport.land(plane2) + airport.take_off(plane) + expect(airport.hangar).not_to include(plane) + end + + it 'raises an error when there are no planes in the hangar' do + expect { subject.take_off(plane) }.to raise_error 'No planes in hangar.' + end + + it 'should raise error if flying plane tries take_off again.' do + allow(subject).to receive(:storm?).and_return false + subject.land(plane) + expect { subject.take_off(plane2) }.to raise_error 'Plane not in hangar.' + end + + it 'raises error when plane tries to take off during storm' do + allow(subject).to receive(:storm?).and_return false + subject.land(plane) + allow(subject).to receive(:storm?).and_return true + expect { subject.take_off(plane) }.to raise_error 'Weather stormy, take off not available.' + end + + it 'should not raise an error on plane take off when weather clear' do + allow(subject).to receive(:storm?).and_return false + subject.land(plane) + expect { subject.take_off(plane) }.to_not raise_error + end + end +end \ No newline at end of file diff --git a/spec/feature_test.rb b/spec/feature_test.rb new file mode 100644 index 0000000000..d1509855d9 --- /dev/null +++ b/spec/feature_test.rb @@ -0,0 +1,65 @@ +require_relative '../lib/airport.rb' +# require_relative '../lib/weather.rb' + + +# Haven't looked into feature tests yet so just recording irb tests. +# Use the drop-downs and remove hashes from code you wish to try out. +# Please do this one at a time! +# Rogue weather spells may hit during tests... + +airport1 = Airport.new +airport2 = Airport.new +airport3 = Airport.new(2) + +plane1 = Plane.new +plane2 = Plane.new +plane3 = Plane.new + +weather1 = Weather.new + +# [X] Plane can land (store plane) & take off (return plane) + # p airport1.land(plane1) + # p airport1.take_off(plane1) + +# [X] Remove plane from hangar when taking off + # p airport1.land(plane1) + # p airport1 + # p airport1.take_off(plane1) + # p airport1 + +# [X] Default capacity of 10 planes vs. setting capacity at 2 + # p airport1 + # p airport3 + +# [X] Error when hangar is full + # p airport3.land(plane1) + # p airport3.land(plane2) + # p airport3.land(plane3) + +# [X] Error when hangar empty + # p airport1.take_off(plane1) + +# [X] Error if grounded plane tries landing in same airport again + # p airport1.land(plane1) + # p airport1.land(plane1) + +# [ ] Error if grounded plane tries landing in another airport + # p airport1.land(plane1) + # p airport2.land(plane1) + +# [X] Planes can only take off from airport they are in + # p airport1.land(plane1) + # p airport2.land(plane2) + # p airport2.take_off(plane1) + +# [X] landing/takeoff error if weather is stormy + # p airport1.land(plane1) + # p airport1.take_off(plane1) + +# [X] Check if weather / storm method works + # p weather1.storm? + # p weather1.storm? + # p weather1.storm? + # p weather1.storm? + # p weather1.storm? + # p weather1.storm? diff --git a/spec/plane_spec.rb b/spec/plane_spec.rb new file mode 100644 index 0000000000..1c7e737139 --- /dev/null +++ b/spec/plane_spec.rb @@ -0,0 +1,20 @@ +require_relative '../lib/plane.rb' + +describe Plane do + + describe '#ground' do + it { is_expected.to respond_to :ground } + + it 'should return false if plane is flying' do + expect(subject.ground).to be_falsey + end + end + + describe '#air' do + it { is_expected.to respond_to :air } + + it 'should return true if plane is flying' do + expect(subject.air).to be_truthy + end + end +end \ No newline at end of file diff --git a/spec/weather_spec.rb b/spec/weather_spec.rb new file mode 100644 index 0000000000..9a08fcf796 --- /dev/null +++ b/spec/weather_spec.rb @@ -0,0 +1,12 @@ +require_relative '../lib/weather.rb' + +describe Weather do + + describe '#storm?' do + it { is_expected.to respond_to :storm? } + + it 'returns true if theres a storm.' do + expect(subject.storm?).to be(true).or be(false) + end + end +end \ No newline at end of file