diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..ba07ed4 --- /dev/null +++ b/.rspec @@ -0,0 +1,4 @@ + +--color +--format d +--require spec_helper diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..9ff5402 --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ + +source 'https://rubygems.org' + +gem 'rspec' +gem 'guard-rspec', require: false diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..ddfc7b9 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,65 @@ +GEM + remote: https://rubygems.org/ + specs: + coderay (1.1.1) + diff-lcs (1.2.5) + ffi (1.9.14) + formatador (0.2.5) + guard (2.14.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (~> 1.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + lumberjack (1.0.10) + method_source (0.8.2) + nenv (0.3.0) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rb-fsevent (0.9.8) + rb-inotify (0.9.7) + ffi (>= 0.5.0) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + ruby_dep (1.5.0) + shellany (0.0.1) + slop (3.6.0) + thor (0.19.1) + +PLATFORMS + ruby + +DEPENDENCIES + guard-rspec + rspec + +BUNDLED WITH + 1.13.5 diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..3215f01 --- /dev/null +++ b/Guardfile @@ -0,0 +1,70 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +# directories %w(app lib config test spec features) \ +# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")} + +## Note: if you are using the `directories` clause above and you are not +## watching the project directory ('.'), then you will want to move +## the Guardfile to a watched dir and symlink it back, e.g. +# +# $ mkdir config +# $ mv Guardfile config/ +# $ ln -s config/Guardfile . +# +# and, you'll have to watch "config/Guardfile" instead of "Guardfile" + +# Note: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: "bundle exec rspec" do + require "guard/rspec/dsl" + dsl = Guard::RSpec::Dsl.new(self) + + # Feel free to open issues for suggestions and improvements + + # RSpec files + rspec = dsl.rspec + watch(rspec.spec_helper) { rspec.spec_dir } + watch(rspec.spec_support) { rspec.spec_dir } + watch(rspec.spec_files) + + # Ruby files + ruby = dsl.ruby + dsl.watch_spec_files_for(ruby.lib_files) + + # Rails files + rails = dsl.rails(view_extensions: %w(erb haml slim)) + dsl.watch_spec_files_for(rails.app_files) + dsl.watch_spec_files_for(rails.views) + + watch(rails.controllers) do |m| + [ + rspec.spec.call("routing/#{m[1]}_routing"), + rspec.spec.call("controllers/#{m[1]}_controller"), + rspec.spec.call("acceptance/#{m[1]}") + ] + end + + # Rails config changes + watch(rails.spec_helper) { rspec.spec_dir } + watch(rails.routes) { "#{rspec.spec_dir}/routing" } + watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } + + # Capybara features specs + watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") } + watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| + Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" + end +end diff --git a/lib/viking.rb b/lib/viking.rb index e33b1c4..2e55427 100644 --- a/lib/viking.rb +++ b/lib/viking.rb @@ -13,7 +13,6 @@ def initialize(name="RandomViking", health = 100, strength = 10, weapon = nil) @weapon = weapon end - def attack(target) puts "#{name} is attacking #{target.name}!" target.receive_attack(damage_dealt) @@ -68,15 +67,15 @@ def check_death end # Run script -oleg = Viking.new("Oleg") -sven = Viking.new("Sven") -oleg.attack(sven) -oleg.pick_up_weapon(Bow.new(2)) -3.times { oleg.attack(sven) } -sven.attack(oleg) -sven.pick_up_weapon(Axe.new) -3.times {sven.attack(oleg)} -puts "\nInspecting vikings:\n" -puts oleg.inspect -puts sven.inspect -puts "\n...thanks for playing.\n\n" \ No newline at end of file +#oleg = Viking.new("Oleg") +#sven = Viking.new("Sven") +#oleg.attack(sven) +#oleg.pick_up_weapon(Bow.new(2)) +#3.times { oleg.attack(sven) } +#sven.attack(oleg) +#sven.pick_up_weapon(Axe.new) +#3.times {sven.attack(oleg)} +#puts "\nInspecting vikings:\n" +#puts oleg.inspect +#puts sven.inspect +#puts "\n...thanks for playing.\n\n" diff --git a/lib/warmup.rb b/lib/warmup.rb index 32cc58e..50c127a 100644 --- a/lib/warmup.rb +++ b/lib/warmup.rb @@ -1,18 +1,21 @@ + class Warmup - + # This is a user input and command-line-output # test. You need to stub out `gets` to make it work # And can stub out `puts` just for fun def gets_shout shout = gets.chomp.upcase + # shout = self.gets.chomp.upcase + # self.gets should evaluate to "string\n" # This is a side effect. Test it if you'd like! - # (optional). + # (optional). puts shout return shout end - + # For your spec for this one, pass in a plain old double # that can accept a #size method and return something @@ -22,15 +25,15 @@ def triple_size(array) return array.size * 3 end - + # Tricky! This method has side effects. Pay attention to # which object each method is called on. Remember that # "bang!" methods are in-place (destructive). # # For this method, write separate tests to show: # 1. The string you pass in receives the #upcase! - # method call, - # 2. The string you pass in receives the #reverse! + # method call, + # 2. The string you pass in receives the #reverse! # method call, # 3. Your method actually returns a completely different # object than the one you passed in diff --git a/lib/weapons/bow.rb b/lib/weapons/bow.rb index 18563ac..5794cdb 100644 --- a/lib/weapons/bow.rb +++ b/lib/weapons/bow.rb @@ -1,8 +1,9 @@ + require_relative 'weapon' class Bow < Weapon attr_reader :arrows - + def initialize(arrows = 10) super("Bow", 2) @arrows = arrows @@ -20,4 +21,4 @@ def out_of_arrows? @arrows <= 0 end -end \ No newline at end of file +end diff --git a/spec/bow_spec.rb b/spec/bow_spec.rb index e666e54..c0e5ba1 100644 --- a/spec/bow_spec.rb +++ b/spec/bow_spec.rb @@ -1 +1,42 @@ -# Your code here \ No newline at end of file + +require 'weapons/bow' + +describe Bow do + let(:bow) { Bow.new } + + context 'default bow configuration' do + it 'is instantiated with 10 arrows' do + default_bow = Bow.new + expect(default_bow.arrows).to eq(10) + end + end + + context 'custom bow configuration' do + it 'is instantiated with given number of arrows' do + arrows = 1010 + custom_bow = Bow.new(arrows) + expect(custom_bow.arrows).to eq(arrows) + end + end + + describe '#arrows' do + + it 'returns a number greater than or equal to 0' do + expect(bow.arrows).to be >= 0 + end + + end + + describe "#use" do + it "decreases arrow count by one" do + bow.use + expect(bow.arrows).to eq(9) + end + + it "throws an error if arrow count is 0" do + empty_bow = Bow.new(0) + expect{ empty_bow.use }.to raise_error(RuntimeError) # Should be RuntimeError? or Actual message? + end + end + +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..47b39ce --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,103 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/spec/viking_spec.rb b/spec/viking_spec.rb index e666e54..c232c2f 100644 --- a/spec/viking_spec.rb +++ b/spec/viking_spec.rb @@ -1 +1,144 @@ -# Your code here \ No newline at end of file + +require 'viking' + +describe Viking do + let(:default_viking) { Viking.new } + before { allow(STDOUT).to receive(:puts) } + + describe '#initialize' do + describe 'custom configuration' do + it 'can be instantiated with a given name' do + name = 'Sven' + sven = Viking.new(name) + expect(sven.name).to eq(name) + end + + it 'can be instantiated with a given health' do + health = 6000 + sven = Viking.new("", health) + expect(sven.health).to eq(health) + end + end + + describe 'default configuration' do + it 'is instantiated without a weapon' do + expect(default_viking.weapon).to be nil + end + end + end + + describe '#health=' do + it 'cannot have health manually altered after initialization' do + expect{ default_viking.health = 6000 }.to raise_error(NoMethodError) + end + end + + describe '#pick_up_weapon' do + it 'raises an error unless argument is a weapon' do + harmless = double + expect { default_viking.pick_up_weapon(harmless) }.to raise_error("Can't pick up that thing") + end + + context 'passed valid argument' do + let(:weapon) { double } + #let(:weapon, :other_weapon) { double, double } + #let(:weapon, :other_weapon) { [double, double] } + before(:each) do + allow(weapon).to receive(:is_a?).with(Weapon).and_return(true) + end + + it 'sets vikings weapon to argument' do + default_viking.pick_up_weapon(weapon) + expect(default_viking.weapon).to eq(weapon) + end + + it 'replaces vikings weapon with argument' do + default_viking.pick_up_weapon(weapon) + other_weapon = double + allow(other_weapon).to receive(:is_a?).with(Weapon).and_return(true) + default_viking.pick_up_weapon(other_weapon) + expect(default_viking.weapon).to eq(other_weapon) + end + end + end + + describe '#drop_weapon' do + it 'sets the vikings weapon to nothing' do + weapon = "axe" + viking_with_weapon = Viking.new("", 10, 10, weapon) + viking_with_weapon.drop_weapon + expect(viking_with_weapon.weapon).to be nil + end + end + + describe "#receive_attack" do + it 'reduces viking\'s health by given amount' do + damage = 3 + starting_health = default_viking.health + default_viking.receive_attack(damage) + expect(default_viking.health).to eq(starting_health - damage) + end + + it 'calls the take damage method on the viking' do + expect(default_viking).to receive(:take_damage).with(3) + default_viking.receive_attack(3) + end + end + + describe "#attack" do + let(:target_viking) { Viking.new } + let(:damage) { 1 } + + it 'reduces the targets health by some number' do + allow(default_viking).to receive(:damage_dealt).and_return(damage) + starting_health = target_viking.health + default_viking.attack(target_viking) + expect(target_viking.health).to eq(starting_health - damage) + end + + it 'calls the #take_damage method on the target' do + allow(default_viking).to receive(:damage_dealt).and_return(damage) + expect(target_viking).to receive(:take_damage).with(damage) + default_viking.attack(target_viking) + end + + it 'runs #damage_with_fist if viking has no weapon' do + expect(default_viking).to receive(:damage_with_fists).and_return(damage) + default_viking.attack(target_viking) + end + + it 'deals damage based on fist multiplier times strength when Viking has no weapon' do + # 2.5 comes from fist multiplier of .25 and str = 10 + expect(target_viking).to receive(:take_damage).with(2.5) + default_viking.attack(target_viking) + end + + it 'attacking with a weapon calls damage_with_weapon' do + weapon = double(is_a?: true) + default_viking.pick_up_weapon(weapon) + expect(default_viking).to receive(:damage_with_weapon).and_return(0) + default_viking.attack(target_viking) + end + + it 'attacking with a weapon deals damage equal to the vikings strength times the weapon\'s multiplier' do + weapon = double(use: 7, is_a?: true) + default_viking.pick_up_weapon(weapon) + expect(target_viking).to receive(:take_damage).with(70) + default_viking.attack(target_viking) + end + + it 'attacking with an empty bow uses fists instead' do + bow = double("bow", is_a?: true, out_of_arrows?: true) + allow(bow).to receive(:use).and_raise("Out of arrows") + default_viking.pick_up_weapon(bow) + expect(default_viking).to receive(:damage_with_fists).and_return(0) + default_viking.attack(target_viking) + end + + it 'a viking to 0 or less health raises an error' do + unhealthy_viking = Viking.new('Keith', 0) + expect{ unhealthy_viking.receive_attack(damage)}.to raise_error("Keith has Died...") + end + end + +end diff --git a/spec/warmup_spec.rb b/spec/warmup_spec.rb new file mode 100644 index 0000000..d2a86ec --- /dev/null +++ b/spec/warmup_spec.rb @@ -0,0 +1,58 @@ + +require 'warmup' + +describe Warmup do + let(:warmup) { Warmup.new } + before { allow(STDOUT).to receive(:puts) } + + describe '#gets_shout' do + before(:each) do + allow(warmup).to receive(:gets).and_return("string\n") + end + + it 'puts shout to stdout' do + expect{ warmup.gets_shout }.to output(/^S.+/).to_stdout + end + + it 'gets input from stdin, removes trailing whitespace, and upcases it' do + expect(warmup.gets_shout).to eq("STRING") + end + + end + + describe '#triple_size' do + + it 'returns an integer that is three times the length of the argument array' do + array = double(size: 8) + expect(warmup.triple_size(array)).to eq(24) + end + end + + + describe '#calls_some_methods' do + let(:string) do + double("String") + end + + before(:each) do + allow(string).to receive(:empty?).and_return(false) + allow(string).to receive(:upcase!).and_return(string) + allow(string).to receive(:reverse!) + end + + it 'calls upcase! on argument string' do + expect(string).to receive(:upcase!) + warmup.calls_some_methods(string) + end + + it 'calls reverse! on argument string' do + expect(string).to receive(:reverse!) + warmup.calls_some_methods(string) + end + + it 'returns unique object' do + returned_string = warmup.calls_some_methods(string) + expect(returned_string.object_id).not_to eql(string.object_id) + end + end +end