<commit_before>describe IOEventLoop do
  subject(:instance) { IOEventLoop.new }

  it { is_expected.to be_a FiberedEventLoop }

  describe "#start" do
    subject { instance.start }

    context "when it has no timers and nothing to watch" do
      before { expect(instance).to receive(:stop).and_call_original }
      before { expect(instance).to receive(:trigger).with(:iteration) }
      it { is_expected.to be nil }
    end

    context "when it has nothing to watch but a timer to wait for" do
      before { instance.timers.after(0.01, &callback) }
      let(:callback) { proc{} }
      before { expect(callback).to receive(:call) }

      before { expect(instance).to receive(:trigger).with(:iteration).exactly(3).times }
      before { expect(instance).to receive(:stop).and_call_original }
      it { is_expected.to be nil }
    end

    context "when it has an IO object waiting for a single event" do
      let(:pipe) { IO.pipe }
      let(:reader) { pipe[0] }
      let(:writer) { pipe[1] }

      context "when its waiting to be readable" do
        before { instance.timers.after(0.01) { writer.write 'Wake up!'; writer.close } }
        before { instance.wait_for_readable(reader) }

        before { expect(instance).to receive(:trigger).with(:iteration) }
        it { is_expected.to be nil }
        after { expect(reader.read).to eq 'Wake up!' }
      end

      context "when its waiting to be writable" do
        before { instance.wait_for_writable(writer) }

        before { expect(instance).to receive(:trigger).with(:iteration) }
        it { is_expected.to be nil }
        after do
          writer.write 'Hello!'; writer.close
          expect(reader.read).to eq 'Hello!'
        end
      end
    end
  end

  describe "#attach_reader and #detach_reader" do
    subject { instance.start }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    context "when watching readability" do
      before { instance.attach_reader(reader, &callback1) }
      let(:callback1) { proc{ instance.detach_reader(reader) } }

      # make the reader readable
      before { instance.timers.after(0.01) { writer.write 'Message!' } }

      before { expect(callback1).to receive(:call).and_call_original }
      it { is_expected.to be nil }
    end
  end

  describe "#attach_writer and #detach_writer" do
    subject { instance.start }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    context "when watching writability" do
      before { instance.attach_writer(writer, &callback1) }
      let(:callback1) { proc{ instance.detach_writer(writer) } }

      before { expect(callback1).to receive(:call).and_call_original }
      it { is_expected.to be nil }
    end
  end

  describe "#wait_for_result with timeout" do
    subject do
      result = instance.wait_for_result(:id, 0.02) { RuntimeError.new "Time's up!" }
      (result.is_a? RuntimeError) ? raise(result) : result
    end

    context "when the result arrives in time" do
      before { instance.timers.after(0.01) { instance.hand_result_to(:id, :result) } }
      it { is_expected.to be :result }
    end

    context "when evaluation of result is too slow" do
      it { is_expected.to raise_error "Time's up!" }
    end
  end

  describe "#wait_for_readable" do
    subject { instance.wait_for_readable(reader, *timeout, &timeout_callback) }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    let(:timeout) { nil }
    let(:timeout_callback) { nil }

    context "when it has a timeout" do
      let(:timeout) { 0.02 }
      let(:timeout_callback) { proc{ raise "Time's up!" } }

      context "when readable in time" do
        before { instance.timers.after(0.01) { writer.write 'Wake up!' } }
        it { is_expected.to be :readable }
      end

      context "when not readable in time" do
        it { is_expected.to raise_error "Time's up!" }
      end
    end
  end

  describe "#wait_for_writable" do
    subject { instance.wait_for_writable(writer, *timeout, &timeout_callback) }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    let(:timeout) { nil }
    let(:timeout_callback) { nil }

    context "when it has a timeout" do
      let(:timeout) { 0.02 }
      let(:timeout_callback) { proc{ raise "Time's up!" } }

      # jam pipe: default pipe buffer size on linux is 65536
      before { writer.write('a' * 65536) }

      context "when writable in time" do
        before { instance.timers.after(0.01) { reader.read(65536) } } # clear the pipe
        it { is_expected.to be :writable }
      end

      context "when not writable in time" do
        it { is_expected.to raise_error "Time's up!" }
      end
    end
  end
end<commit_msg>refactored specs for waiting for readability and writability<commit_after>describe IOEventLoop do
  subject(:instance) { IOEventLoop.new }

  it { is_expected.to be_a FiberedEventLoop }

  describe "#start" do
    subject { instance.start }

    context "when it has no timers and nothing to watch" do
      before { expect(instance).to receive(:stop).and_call_original }
      before { expect(instance).to receive(:trigger).with(:iteration) }
      it { is_expected.to be nil }
    end

    context "when it has nothing to watch but a timer to wait for" do
      before { instance.timers.after(0.01, &callback) }
      let(:callback) { proc{} }
      before { expect(callback).to receive(:call) }

      before { expect(instance).to receive(:trigger).with(:iteration).exactly(3).times }
      before { expect(instance).to receive(:stop).and_call_original }
      it { is_expected.to be nil }
    end

    context "when it has an IO object waiting for a single event" do
      let(:pipe) { IO.pipe }
      let(:reader) { pipe[0] }
      let(:writer) { pipe[1] }

      context "when its waiting to be readable" do
        before { instance.timers.after(0.01) { writer.write 'Wake up!'; writer.close } }
        before { instance.wait_for_readable(reader) }

        before { expect(instance).to receive(:trigger).with(:iteration) }
        it { is_expected.to be nil }
        after { expect(reader.read).to eq 'Wake up!' }
      end

      context "when its waiting to be writable" do
        before { instance.wait_for_writable(writer) }

        before { expect(instance).to receive(:trigger).with(:iteration) }
        it { is_expected.to be nil }
        after do
          writer.write 'Hello!'; writer.close
          expect(reader.read).to eq 'Hello!'
        end
      end
    end
  end

  describe "#attach_reader and #detach_reader" do
    subject { instance.start }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    context "when watching readability" do
      before { instance.attach_reader(reader, &callback1) }
      let(:callback1) { proc{ instance.detach_reader(reader) } }

      # make the reader readable
      before { instance.timers.after(0.01) { writer.write 'Message!' } }

      before { expect(callback1).to receive(:call).and_call_original }
      it { is_expected.to be nil }
    end
  end

  describe "#attach_writer and #detach_writer" do
    subject { instance.start }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    context "when watching writability" do
      before { instance.attach_writer(writer, &callback1) }
      let(:callback1) { proc{ instance.detach_writer(writer) } }

      before { expect(callback1).to receive(:call).and_call_original }
      it { is_expected.to be nil }
    end
  end

  describe "#wait_for_result with timeout" do
    subject do
      result = instance.wait_for_result(:id, 0.02) { RuntimeError.new "Time's up!" }
      (result.is_a? RuntimeError) ? raise(result) : result
    end

    context "when the result arrives in time" do
      before { instance.timers.after(0.01) { instance.hand_result_to(:id, :result) } }
      it { is_expected.to be :result }
    end

    context "when evaluation of result is too slow" do
      it { is_expected.to raise_error "Time's up!" }
    end
  end

  describe "#wait_for_readable" do
    subject { instance.wait_for_readable(reader, *timeout, &timeout_callback) }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    shared_examples "for readability" do
      context "when readable after some time" do
        before { instance.timers.after(0.01) { writer.write 'Wake up!' } }
        it { is_expected.to be :readable }
      end
    end

    context "when it waits indefinitely" do
      let(:timeout) { nil }
      let(:timeout_callback) { nil }

      include_examples "for readability"

      context "when never readable" do
        # we do not have enough time to test that
      end
    end

    context "when it has a timeout" do
      let(:timeout) { 0.02 }
      let(:timeout_callback) { proc{ raise "Time's up!" } }

      include_examples "for readability"

      context "when not readable in time" do
        it { is_expected.to raise_error "Time's up!" }
      end
    end
  end

  describe "#wait_for_writable" do
    subject { instance.wait_for_writable(writer, *timeout, &timeout_callback) }

    let(:pipe) { IO.pipe }
    let(:reader) { pipe[0] }
    let(:writer) { pipe[1] }

    # jam pipe: default pipe buffer size on linux is 65536
    before { writer.write('a' * 65536) }

    shared_examples "for writability" do
      context "when writability after some time" do
        before { instance.timers.after(0.01) { reader.read(65536) } } # clear the pipe
        it { is_expected.to be :writable }
      end
    end

    context "when it waits indefinitely" do
      let(:timeout) { nil }
      let(:timeout_callback) { nil }

      include_examples "for writability"

      context "when never writable" do
        # we do not have enough time to test that
      end
    end

    context "when it has a timeout" do
      let(:timeout) { 0.02 }
      let(:timeout_callback) { proc{ raise "Time's up!" } }

      include_examples "for writability"

      context "when not writable in time" do
        it { is_expected.to raise_error "Time's up!" }
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.11450381679389313, 'fraction_numerical': 0.011548248189469564, 'mean_word_length': 2.6838500360490265, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4908240', 'n_tokens_mistral': 3271, 'n_tokens_neox': 3100, 'n_words': 894}