amirrajan / rubymotion-applied

RubyMotion documentation provided by the community. Submit a pull request to the docs for a free one year indie subscription.
Apache License 2.0
49 stars 10 forks source link

Sample tests written with Bacon #117

Open amirrajan opened 5 years ago

amirrajan commented 5 years ago

Here are some sample tests written with bacon. Feel free to add your own.

amirrajan commented 5 years ago
module ADR
describe "rules of world events" do
  [
    { :type => SwampEvent },
    { :type => ShipEvent },
    { :type => IronMineEvent },
    { :type => SulphurMineEvent },
    { :type => HouseEvent },
    { :type => CoalMineEvent },
    { :type => CaveEvent },
    { :type => BattlefieldEvent },
    { :type => BoreholeEvent },
    {
      :type => TownEvent,
      :rolls => [
        # a1    b1    c1    d1    end1
        [ 0.35, 0.45, 0.45, 0.45, 0.45 ],

        # a1    b1    c1    d1    end2
        [ 0.35, 0.45, 0.45, 0.45, 0.95 ],

        # a1    b2    c2    d1    end2
        [ 0.35, 0.95, 0.45, 0.45, 0.95 ],

        # a1    b2    c3    d1    end2
        [ 0.35, 0.95, 0.95, 0.45, 0.95 ],

        # a2    b3    c4    d2    end3
        [ 0.95, 0.45, 0.45, 0.45, 0.45 ],

        # a2    b4    c5    d2    end4
        [ 0.95, 0.95, 0.45, 0.45, 0.95 ],

        # a2    b4    c6    d2    end4
        [ 0.95, 0.95, 0.95, 0.45, 0.95 ],
      ]
    },
    {
      :type => CityEvent,
      :rolls => [
        # a1    b1    c1    d1    end1
        [ 0.35, 0.45, 0.45, 0.45, 0.45 ],

        # a1    b2    c2    d2    end2
        [ 0.35, 0.95, 0.45, 0.95, 0.95 ],

        # a1    b2    c3    d3    end3
        [ 0.35, 0.95, 0.95, 0.95, 0.95 ],

        # a2    b3    c4    d4    end4
        [ 0.75, 0.45, 0.45, 0.45, 0.45 ],

        # a2    b3    c4    d5    end5
        [ 0.75, 0.45, 0.45, 0.95, 0.95 ],

        # a2    b3    c5    d5    end5
        [ 0.75, 0.45, 0.95, 0.95, 0.95 ],

        # a2    b4    c5    d5    end5
        [ 0.75, 0.95, 0.45, 0.45, 0.45 ],

        # a2    b4    c6    d5    end5
        [ 0.75, 0.95, 0.95, 0.45, 0.45 ],

        # a2    b4    c6    d6    end5
        [ 0.75, 0.95, 0.95, 0.95, 0.45 ],

        # a2    b4    c6    d6    end6
        [ 0.75, 0.95, 0.95, 0.95, 0.95 ],

        # a3    b5    c7    d7    end7
        [ 0.95, 0.45, 0.45, 0.45, 0.45 ],

        # a3    b5    c7    d7    end8
        [ 0.95, 0.45, 0.45, 0.45, 0.95 ],

        # a3    b5    c7    d8    end8
        [ 0.95, 0.45, 0.45, 0.95, 0.95 ],

        # a3    b6    c8    d8    end8
        [ 0.95, 0.95, 0.45, 0.95, 0.95 ],

        # a3    b6    c9    d9    end9
        [ 0.95, 0.95, 0.95, 0.95, 0.95 ],
      ]
    },
  ].each do |row|
    it "#{row[:type]}: each scene contains two or fewer options" do
      for_all_scenes_of row[:type], row[:rolls] do |event|
        current_scene(event).should have_one_or_two_options
      end
    end

    it "#{row[:type]}: each scene has text associated with it" do
      for_all_scenes_of row[:type], row[:rolls] do |event|
        current_scene(event)[:text].class.should.equal Array
      end
    end

    it "#{row[:type]}: loot scenes either have a continue and run, or leave option" do
      for_all_scenes_of row[:type], row[:rolls] do |event|
        if current_scene(event)[:loot]
          current_scene(event).should have_loot_specific_options
        end
      end
    end

    it "#{row[:type]}: clears the event at the end (or becomes and outpost)" do
      for_each_completion_of row[:type], row[:rolls] do |world, event|
        if event.becomes_outpost?
          world.landmarks[[30,30]].should.equal :outpost
        elsif event.on_clear_replace_with
          world.landmarks[[30,30]].should.equal event.on_clear_replace_with
        else
          world.cleared[[30,30]].should.equal true
        end
      end
    end

    it "#{row[:type]}: combat scenes only have continue and run" do
      for_all_scenes_of row[:type], row[:rolls] do |event|
        if current_scene(event)[:combat]
          current_scene(event).should have_combat_specific_options
        end
      end
    end

    it "#{row[:type]}: accounts for all scenes" do
      all_scenes = []

      for_all_scenes_of row[:type], row[:rolls] do |event|
        all_scenes << event.current_scene
      end

      event = row[:type].new(game_ready_to_play)
      event.init_scenes
      event.scenes.keys.sort.should.equal all_scenes.uniq.sort
    end
  end

  def for_each_completion_of type, rolls = nil
    game = game_ready_to_play
    event = type.new game
    event.init_scenes
    rolls ||= rolls_for event

    rolls.each do |roll|
      game = game_ready_to_play
      event = type.new game
      event.init_scenes
      turn_index = 0
      Event.stub_roll roll[turn_index]

      until move_forward(event) == :end
        turn_index += 1

        if roll[turn_index] != nil
          Event.stub_roll roll[turn_index]
        end
      end

      yield game.world, event
    end

    "no op".should.equal "no op" #prevents empty specification warning
  end

  def for_all_scenes_of type, rolls
    game = game_ready_to_play
    event = type.new game
    event.init_scenes
    rolls ||= rolls_for event

    rolls.each do |roll|
      game = game_ready_to_play
      event = type.new game
      event.init_scenes
      turn_index = 0
      Event.stub_roll roll[turn_index]

      yield event

      while move_forward(event) != :end
        turn_index += 1

        if roll[turn_index] != nil
          Event.stub_roll roll[turn_index]
        end

        yield event
      end
    end

    "no op".should.equal "no op" #prevents empty specification warning
  end

  def current_scene event
    event.scenes[event.current_scene]
  end

  def move_forward event
    next_scene = current_scene(event)[:options].keys.first

    event.change_scene next_scene

    event.current_scene
  end

  def rolls_for event
    #this method finds all random rolls needed to traverse the event tree
    #it's my attempt to avoid creating a recursive method that generates the tree
    #and then attempts to traverse it

    rolls = []

    event.scenes.keys.each do |key|
      scene = event.scenes[key]

      scene[:options].keys.each do |option_key|
        option = scene[:options][option_key]

        if option[:next_scene].is_a?(Hash)
          option[:next_scene].keys.each do |roll|
            rolls << [roll - 0.05]
          end
        end
      end
    end

    rolls << [1] if rolls.length == 0

    rolls.uniq
  end

  def have_one_or_two_options
    lambda do |scene|
      if(scene[:options].keys.count == 1 or scene[:options].keys.count == 2)
        true
      else
        raise "Scene #{scene} doesn't have the write amount of options"
      end
    end
  end

  def have_combat_specific_options
    lambda do |scene|
      passed = true

      keys = scene[:options].keys

      if keys.count != 2
        passed = false
        message = "combat scene didn't contain exactly two options"
      end

      if !scene[:max_health] or
        !scene[:health] or
        !scene[:attack_delay] or
        !scene[:enemy] or
        !scene[:damage]
        passed = false
        message = "combat scene is missing max_health, health, enemy, damage or attack delay"
      end

      if keys.first != :continue
        passed = false
        message = "combat scene's first option wasn't continue"
      end

      if keys[-1] != :run
        passed = false
        message = "combat scene's last option wasn't run"
      end

      if !passed
        raise "combat scene doesn't have the right stuff (#{message}) #{scene}"
      end

      passed
    end
  end

  def have_loot_specific_options
    lambda do |scene|
      passed = true
      keys = scene[:options].keys
      message = ""

      if keys.count > 2 or keys.count < 1
        passed = false
        message = "loot options where greater than 2 or less then 1"
      end

      guarenteed_loot = false

      scene[:loot].keys.each do |loot_key|
        if scene[:loot][loot_key][:chance] > 0.98
          guarenteed_loot = true
        end
      end

      if !guarenteed_loot
        passed = false
        message = "loot not guranteed for scene"
      end

      if keys.count == 2
        if keys.first != :continue
          passed = false
          message = "it had two options, but the first option wasn't :continue"
        end

        if keys[-1] != :run
          passed = false
          message = "it had two options, but the last option wasn't :run"
        end
      end

      if keys.count == 1
        if keys.first != :leave
          passed = false
          message = "it had one options, but the option wasn't :leave"
        end
      end

      if !passed
        raise "loot scene doesn't have the right stuff (#{message}) #{scene}"
      end

      passed
    end
  end

  def events
    World.event_map.keys.map { |key| World.event_map[key] }
  end

  def game_ready_to_play
    game = Game.new
    game.load
    game.game_state.clear
    game.room.unlock_forest
    game.room.builder_ready
    game.room.unlock_crafts
    game.world.stores[:torch] = 10000
    game.world.stores[:cure_meat] = 10000
    game.world.stores[:jewel] = 10000
    game
  end
end
end
amirrajan commented 5 years ago
module ADR
describe Room do
  before do
    @game = Game.new
    @game.load
    @game.game_state.clear
    @tick_executed = false
  end

  def update
    @tick_executed = true
  end

  it "title is based off of fire" do
    @game.room.title.should.equal "a dark room"
  end

  describe "stoking and lighting fire after forest" do
    before do
      @game = Game.new
      @game.load
      @game.game_state.clear
      @game.room.light_fire
      @game.room.unlock_forest
    end

    it "requires 1 wood to stoke fire" do
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.begining_of_game.should.equal false
      @game.room.stoke.should.equal true
      @game.stores[:wood].should.equal 3
    end

    it "isn't preformed if there aren't enough funds" do
      @game.room.stoke_ready_after.times { @game.tick }
      @game.stores[:wood] = 0
      @game.room.stoke.should.equal false
    end

    it "requires 5 wood to light fire" do
      @game.room.fire = :dead
      @game.room.light_fire.should.equal false
      @game.stores[:wood] = 10
      @game.room.light_fire.should.equal true
      @game.stores[:wood].should.equal 5
    end
  end

  describe "starting and stoking fire" do
    it "a fire can be lit" do
      @game.room.light_fire
      @game.room.fire.should.equal :burning
    end

    it "allows stoking after a timer interval has passed" do
      @game.room.light_fire

      @game.room.can_stoke?.should.equal false

      @game.room.stoke_ready_after.times do |i|
        @game.room.current_stoke_ticks.should.equal i
        @game.tick
      end

      @game.room.can_stoke?.should.equal true
    end

    it "stoke is ignored if it cannot stoke" do
      @game.room.light_fire

      @game.room.can_stoke?.should.equal false

      @game.room.stoke

      @game.room.fire.should.equal :burning
    end

    it "current stoke ticks doesn't surpass ready ticks" do
      @game.room.light_fire

      (@game.room.stoke_ready_after + 1).times do |i|
        @game.tick
      end

      @game.room.current_stoke_ticks.should.equal @game.room.stoke_ready_after
    end

    it "stoke ticks remains zero if fire is dead" do
      @game.tick

      @game.room.current_stoke_ticks.should.equal 0
    end

    it "stoking interval and fire status increase reset after stoking" do
      @game.room.light_fire
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.stoke
      @game.room.fire.should.equal :roaring
      @game.room.can_stoke?.should.equal false
    end

    it "initialize the game with fire state" do
      @game.room.tick

      fire_history.last.should.equal "the fire is dead."
    end

    it "notifies the state of the fire" do
      @game.room.light_fire

      @game.room.tick

      fire_history.last.should.equal "the fire is burning."
    end

    it "records fire state everytime the fire is stoked" do
      @game.tick
      @game.room.light_fire
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.stoke
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.stoke
      @game.tick

      fire_history[0].should.equal "the fire is dead."
      fire_history[1].should.equal "the fire is burning."
      fire_history[2].should.equal "the fire is roaring."
      fire_history[3].should.equal "the fire is roaring."
    end

    def fire_history
      @game.history.select { |h| h.match /^the fire/ }
    end
  end

  describe "cooling fire" do
    it "cools if it hasn't been stoked" do
      @game.room.light_fire
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.stoke
      @game.room.fire.should.equal :roaring
      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :burning
      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :flickering
      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :smoldering
      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :dead
      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :dead
    end

    it "resets cooling if fire is stoked" do
      @game.room.light_fire
      @game.room.stoke_ready_after.times { @game.tick }
      @game.room.stoke
      @game.room.fire.should.equal :roaring
      (@game.room.cool_fire_after - 1).times { @game.tick }
      @game.room.stoke
      (@game.room.cool_fire_after - 1).times { @game.tick }
      @game.room.fire.should.equal :roaring
    end
  end

  it "scripted unlock of forest" do
    @game.room.light_fire

    @game.room.builder_status_change_after.times { @game.tick }

    @game.room.forest_unlocked?.should.equal false

    @game.room.builder_status_change_after.times { @game.tick }

    @game.room.forest_unlocked?.should.equal true

    @game.stores[:wood].should.equal 4
  end

  describe "room heating" do
    it "room heats up relative to fire's current state, but doesn't move past" do
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :freezing
      @game.room.light_fire
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :cold
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :mild
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :warm
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :warm

      @game.room.stoke
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :hot
    end

    it "records temp changes" do
      @game.tick
      @game.room.light_fire
      @game.room.room_temp_changes_after.times { @game.tick }

      temperature_history[0].should.equal "the room is cold."
      temperature_history[1].should.equal "the room is mild."
    end

    it "records cooling temperatures" do
      @game.tick
      @game.room.light_fire
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :warm
      @game.room.stoke

      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :hot

      @game.room.cool_fire_after.times { @game.tick }
      @game.room.fire.should.equal :burning

      @game.room.room_temp_changes_after.times { @game.tick }
      @game.room.temperature.should.equal :warm

      temperature_history.last.should.equal "the room is warm."
    end

    def temperature_history
      @game.history.select { |h| h.match /the room/ }
    end
  end

  it "builder squence" do
    @game.room.light_fire

    @game.room.builder_status_change_after.times { @game.tick }

    @game.history
      .select { |h| h.match /from the windows/ }
      .first
      .should
      .equal "the light from the fire spills from the windows, out into the dark."

    @game.room.builder_status_change_after.times { @game.tick }

    @game.history
      .select { |h| h.match /stumbles/ }
      .count.should.equal 1

    @game.room.room_temp_changes_after.times { @game.tick }
    @game.room.builder_status_change_after.times { @game.tick }

    @game.history
      .select { |h| h.match /mumbles/ }
      .count.should.equal 1

    @game.room.builder_status_change_after.times { @game.tick }

    @game.history
      .select { |h| h.match /calms/ }
      .count.should.equal 1
  end
end
end