Skip to content

Commit

Permalink
Add unit tests and run them with gh actions
Browse files Browse the repository at this point in the history
  • Loading branch information
arirusso committed Aug 17, 2022
1 parent bde1b66 commit a01d2b4
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 49 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
name: CI
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
ruby-version:
- "2.4"
- "2.7"
- "3.0"
- "3.1"
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v1

- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true

- name: Run Unit Tests
run: |
bundle exec rake spec:unit
lint:
strategy:
matrix:
Expand Down
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ begin
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:spec)
RSpec::Core::RakeTask.new('spec:unit') do |t|
t.pattern = 'spec/unit/*_spec.rb'
end
RSpec::Core::RakeTask.new('spec:integration') do |t|
t.pattern = 'spec/integration/*_spec.rb'
end

task default: :spec
rescue LoadError
Expand Down
1 change: 0 additions & 1 deletion lib/midi-eye.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
require 'forwardable'
require 'midi-message'
require 'nibbler'
require 'unimidi'

# classes
require 'midi-eye/event_handlers'
Expand Down
30 changes: 15 additions & 15 deletions lib/midi-eye/event_handlers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module MIDIEye
class EventHandlers
extend Forwardable

Event = Struct.new(:handler, :message)
EventHandler = Struct.new(:conditions, :proc, :name)
EnqueuedEvent = Struct.new(:handler, :event)

def_delegators :@handlers, :count

Expand Down Expand Up @@ -52,35 +52,35 @@ def handle_enqueued
counter
end

# Enqueue all events with the given message
# Enqueue the given event for all handlers
# @return [Array<Hash>]
def enqueue_all(message)
@handlers.map { |handler| enqueue(handler, message) }
def enqueue(event)
@handlers.map { |handler| enqueue_event_for_handler(handler, event) }
end

# Add an event to the trigger queue
private

# For the given handler, add an event to the queue
# @return [Hash]
def enqueue(handler, message)
event = Event.new(handler, message)
@event_queue << event
event
def enqueue_event_for_handler(handler, event)
enqueued_event = EnqueuedEvent.new(handler, event)
@event_queue << enqueued_event
enqueued_event
end

private

# Does the given message meet the given conditions?
def meets_conditions?(conditions, message)
conditions.map { |key, value| condition_met?(message, key, value) }.all?
end

# Trigger an event
def handle_event(event)
handler = event.handler
def handle_event(shifted_event)
handler = shifted_event.handler
conditions = handler.conditions
return unless conditions.nil? || meets_conditions?(conditions, event[:message][:message])
return unless conditions.nil? || meets_conditions?(conditions, shifted_event.event[:message])

begin
handler.proc.call(event[:message])
handler.proc.call(shifted_event.event)
rescue StandardError => e
Thread.main.raise(e)
end
Expand Down
22 changes: 9 additions & 13 deletions lib/midi-eye/listener.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ def remove_input(inputs)
alias remove_inputs remove_input

# Start listening for MIDI messages
# @params [Hash] options
# @option options [Boolean] :background Run in a background thread
# @params [Boolean] background Run in a background thread (default: true)
# @return [MIDIEye::Listener] self
def run(options = {})
def run(background: true)
listen
join if options[:background].nil?
join unless background
self
end
alias start run
Expand Down Expand Up @@ -86,13 +85,6 @@ def join
self
end

# Deletes the event with the given name (for backwards compat)
# @param [String, Symbol] event_name
# @return [Boolean]
def delete_event(event_name)
!@event_handlers.delete(event_name).nil?
end

# Add an event to listen for
# @param [Hash] options
# @return [MIDIEye::Listener] self
Expand All @@ -108,21 +100,25 @@ def listen_for(options = {}, &callback)
def poll
@sources.each do |input|
input.poll do |objs|
objs.each { |batch| input_to_messages(batch) }
handle_new_input(objs)
end
end
end

private

def handle_new_input(objs)
objs.each { |batch| input_to_messages(batch) }
end

def input_to_messages(batch)
messages = [batch[:messages]].flatten.compact
messages.each do |message|
data = {
message: message,
timestamp: batch[:timestamp]
}
@event_handlers.enqueue_all(data)
@event_handlers.enqueue(data)
end
end

Expand Down
5 changes: 3 additions & 2 deletions lib/midi-eye/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def initialize(input)
def poll(&block)
messages = @device.buffer.slice(@pointer, @device.buffer.length - @pointer)
@pointer = @device.buffer.length
messages.compact.each { |raw_message| handle_message(raw_message, &block) }
messages.compact.map { |raw_message| handle_message(raw_message, &block) }
end

# If this source was created from the given input
Expand All @@ -42,7 +42,8 @@ def handle_message(raw_message)
nil
end
objects = [parsed_messages].flatten.compact
yield(objects)
yield(objects) if block_given?
objects
end
end
end
14 changes: 0 additions & 14 deletions spec/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,3 @@

require 'rspec'
require 'midi-eye'

module SpecHelper
module_function

def devices
if @devices.nil?
@devices = {}
{ input: UniMIDI::Input, output: UniMIDI::Output }.each do |type, klass|
@devices[type] = klass.gets
end
end
@devices
end
end
17 changes: 17 additions & 0 deletions spec/integration/helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require 'unimidi'

module IntegrationSpecHelper
module_function

def devices
if @devices.nil?
@devices = {}
{ input: UniMIDI::Input, output: UniMIDI::Output }.each do |type, klass|
@devices[type] = klass.gets
end
end
@devices
end
end
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# frozen_string_literal: true

require 'helper'
require 'integration/helper'

describe MIDIEye do
let(:input) { SpecHelper.devices[:input] }
let(:output) { SpecHelper.devices[:output] }
let(:input) { IntegrationSpecHelper.devices[:input] }
let(:output) { IntegrationSpecHelper.devices[:output] }
let(:listener) { MIDIEye::Listener.new(input) }
before { sleep 0.2 }

Expand Down Expand Up @@ -110,7 +111,7 @@
end
end

describe '#delete_event' do
describe 'delete event' do
it 'deletes event' do
event = nil
listener.listen_for(name: :test) do |e|
Expand All @@ -121,7 +122,7 @@
sleep 0.5

expect(listener.event_handlers.count).to eq(1)
listener.delete_event(:test)
listener.event_handlers.delete(:test)
expect(listener.event_handlers.count).to eq(0)
end
end
Expand Down
75 changes: 75 additions & 0 deletions spec/unit/event_handlers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require 'helper'

describe MIDIEye::EventHandlers do
let(:event_handlers) { MIDIEye::EventHandlers.new }
let(:event_handler1) { proc { |event| "#{event} 1" } }
let(:event_handler2) { proc { |event| "#{event} 2" } }
let(:event1) do
{
message: 'a message',
timestamp: Time.now.to_i
}
end
let(:event2) do
{
message: 'another message',
timestamp: Time.now.to_i
}
end

describe '#delete' do
it 'deletes an event handler' do
expect(event_handlers.count).to eq(0)
event_handlers.add(name: :test, &event_handler1)
expect(event_handlers.count).to eq(1)
event_handlers.delete(:test)
expect(event_handlers.count).to eq(0)
end
end

describe '#clear' do
it 'deletes all event handlers' do
expect(event_handlers.count).to eq(0)
event_handlers.add(name: :test, &event_handler1)
event_handlers.add(name: :test, &event_handler2)
event_handlers.clear
expect(event_handlers.count).to eq(0)
end
end

describe '#add' do
it 'adds an event handler' do
expect(event_handlers.count).to eq(0)
event_handlers.add(name: :test, &event_handler1)
expect(event_handlers.count).to eq(1)
end
end

describe '#enqueue' do
it 'enqueues an event' do
expect(event_handlers.count).to eq(0)
event_handlers.add(name: :test, &event_handler1)
event_handlers.enqueue(event1)
event_handlers.enqueue(event2)

expect(event_handlers.handle_enqueued).to eq(2)
end
end

describe '#handle_enqueued' do
it 'processes the events and returns the number of events processed' do
expect(event_handler1).to receive(:call).exactly(:twice)
expect(event_handler2).to receive(:call).exactly(:twice)
expect(event_handlers.count).to eq(0)
event_handlers.add(name: :test, &event_handler1)
event_handlers.add(name: :test, &event_handler2)
expect(event_handlers.count).to eq(2)
event_handlers.enqueue(event1)
event_handlers.enqueue(event2)

expect(event_handlers.handle_enqueued).to eq(4)
end
end
end

0 comments on commit a01d2b4

Please sign in to comment.