wake 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,162 @@
1
+ require 'test/test_helper'
2
+
3
+ if HAVE_REV
4
+
5
+ class Wake::EventHandler::Rev::SingleFileWatcher
6
+ public :type
7
+ end
8
+
9
+ class RevEventHandlerTest < Test::Unit::TestCase
10
+ include Wake
11
+
12
+ SingleFileWatcher = EventHandler::Rev::SingleFileWatcher
13
+
14
+ def setup
15
+ @now = Time.now
16
+ pathname = Pathname.new('foo/bar')
17
+ pathname.stubs(:atime ).returns(@now)
18
+ pathname.stubs(:mtime ).returns(@now)
19
+ pathname.stubs(:ctime ).returns(@now)
20
+ pathname.stubs(:exist?).returns(true)
21
+ SingleFileWatcher.any_instance.stubs(:pathname).returns(pathname)
22
+
23
+ @loop = Rev::Loop.default
24
+ @handler = EventHandler::Rev.new
25
+ @watcher = SingleFileWatcher.new('foo/bar')
26
+ @loop.stubs(:run)
27
+ end
28
+
29
+ def teardown
30
+ SingleFileWatcher.handler = nil
31
+ Rev::Loop.default.watchers.every.detach
32
+ end
33
+
34
+ test "triggers listening state" do
35
+ @loop.expects(:run)
36
+ @handler.listen([])
37
+ end
38
+
39
+ ## SingleFileWatcher
40
+
41
+ test "watcher pathname" do
42
+ @watcher.pathname.should be_kind_of(Pathname)
43
+ @watcher.pathname.to_s.should be(@watcher.path)
44
+ end
45
+
46
+ test "stores reference times" do
47
+ @watcher.pathname.stubs(:atime).returns(:time)
48
+ @watcher.pathname.stubs(:mtime).returns(:time)
49
+ @watcher.pathname.stubs(:ctime).returns(:time)
50
+
51
+ @watcher.send(:update_reference_times)
52
+ @watcher.instance_variable_get(:@reference_atime).should be(:time)
53
+ @watcher.instance_variable_get(:@reference_mtime).should be(:time)
54
+ @watcher.instance_variable_get(:@reference_ctime).should be(:time)
55
+ end
56
+
57
+ test "stores initial reference times" do
58
+ SingleFileWatcher.any_instance.expects(:update_reference_times)
59
+ SingleFileWatcher.new('foo')
60
+ end
61
+
62
+ test "updates reference times on change" do
63
+ @watcher.expects(:update_reference_times)
64
+ @watcher.on_change
65
+ end
66
+
67
+ test "detects event type" do
68
+ trigger_event @watcher, @now, :atime
69
+ @watcher.type.should be(:accessed)
70
+
71
+ trigger_event @watcher, @now, :mtime
72
+ @watcher.type.should be(:modified)
73
+
74
+ trigger_event @watcher, @now, :ctime
75
+ @watcher.type.should be(:changed)
76
+
77
+ trigger_event @watcher, @now, :atime, :mtime
78
+ @watcher.type.should be(:modified)
79
+
80
+ trigger_event @watcher, @now, :mtime, :ctime
81
+ @watcher.type.should be(:modified)
82
+
83
+ trigger_event @watcher, @now, :atime, :ctime
84
+ @watcher.type.should be(:accessed)
85
+
86
+ trigger_event @watcher, @now, :atime, :mtime, :ctime
87
+ @watcher.type.should be(:modified)
88
+
89
+ @watcher.pathname.stubs(:exist?).returns(false)
90
+ @watcher.type.should be(:deleted)
91
+ end
92
+
93
+ ## monitoring file events
94
+
95
+ test "listens for events on monitored files" do
96
+ @handler.listen %w( foo bar )
97
+ @loop.watchers.size.should be(2)
98
+ @loop.watchers.every.path.should include('foo', 'bar')
99
+ @loop.watchers.every.class.uniq.should be([SingleFileWatcher])
100
+ end
101
+
102
+ test "notifies observers on file event" do
103
+ @watcher.stubs(:path).returns('foo')
104
+ @handler.expects(:notify).with('foo', anything)
105
+ @watcher.on_change
106
+ end
107
+
108
+ test "notifies observers of event type" do
109
+ trigger_event @watcher, @now, :atime
110
+ @handler.expects(:notify).with('foo/bar', :accessed)
111
+ @watcher.on_change
112
+
113
+ trigger_event @watcher, @now, :mtime
114
+ @handler.expects(:notify).with('foo/bar', :modified)
115
+ @watcher.on_change
116
+
117
+ trigger_event @watcher, @now, :ctime
118
+ @handler.expects(:notify).with('foo/bar', :changed)
119
+ @watcher.on_change
120
+
121
+ trigger_event @watcher, @now, :atime, :mtime, :ctime
122
+ @handler.expects(:notify).with('foo/bar', :modified)
123
+ @watcher.on_change
124
+
125
+ @watcher.pathname.stubs(:exist?).returns(false)
126
+ @handler.expects(:notify).with('foo/bar', :deleted)
127
+ @watcher.on_change
128
+ end
129
+
130
+ ## on the fly updates of monitored files list
131
+
132
+ test "reattaches to new monitored files" do
133
+ @handler.listen %w( foo bar )
134
+ @loop.watchers.size.should be(2)
135
+ @loop.watchers.every.path.should include('foo')
136
+ @loop.watchers.every.path.should include('bar')
137
+
138
+ @handler.refresh %w( baz bax )
139
+ @loop.watchers.size.should be(2)
140
+ @loop.watchers.every.path.should include('baz')
141
+ @loop.watchers.every.path.should include('bax')
142
+ @loop.watchers.every.path.should exclude('foo')
143
+ @loop.watchers.every.path.should exclude('bar')
144
+ end
145
+
146
+ private
147
+
148
+ def trigger_event(watcher, now, *types)
149
+ watcher.pathname.stubs(:atime).returns(now)
150
+ watcher.pathname.stubs(:mtime).returns(now)
151
+ watcher.pathname.stubs(:ctime).returns(now)
152
+ watcher.instance_variable_set(:@reference_atime, now)
153
+ watcher.instance_variable_set(:@reference_mtime, now)
154
+ watcher.instance_variable_set(:@reference_ctime, now)
155
+
156
+ types.each do |type|
157
+ watcher.pathname.stubs(type).returns(now+10)
158
+ end
159
+ end
160
+ end
161
+
162
+ end # HAVE_REV
@@ -0,0 +1,130 @@
1
+ require 'test/test_helper'
2
+ require 'observer'
3
+
4
+ class MockHandler
5
+ include Observable
6
+ def listen(paths) end
7
+ def refresh(paths) end
8
+ end
9
+
10
+ class TestController < Test::Unit::TestCase
11
+ include Wake
12
+
13
+ def to_p(str)
14
+ Pathname(str).expand_path
15
+ end
16
+
17
+ def setup
18
+ tmpfile = Tempfile.new('foo')
19
+ @script = Script.new( Pathname.new( tmpfile.path ) )
20
+ @handler = MockHandler.new
21
+ Wake.stubs(:handler).returns(MockHandler)
22
+ MockHandler.stubs(:new).returns(@handler)
23
+ @controller = Controller.new(@script)
24
+ end
25
+
26
+ test "triggers listening state on run" do
27
+ @controller.stubs(:monitored_paths).returns %w( foo bar )
28
+ @handler.expects(:listen).with %w( foo bar )
29
+ @controller.run
30
+ end
31
+
32
+ test "parses the script on #run" do
33
+ @script.expects(:parse!)
34
+ @controller.run
35
+ end
36
+
37
+ test "adds itself as handler observer" do
38
+ @controller.handler
39
+ @handler.count_observers.should be(1)
40
+ @handler.delete_observer(@controller)
41
+ @handler.count_observers.should be(0)
42
+ end
43
+
44
+ ## monitored paths list
45
+
46
+ test "fetches monitored paths" do
47
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w(
48
+ a
49
+ b/x.z
50
+ b/c
51
+ b/c/y.z
52
+ ))
53
+ @script.watch('.\.z') { :x }
54
+
55
+ contrl = Controller.new(@script)
56
+ contrl.monitored_paths.should include(to_p('b/x.z'))
57
+ contrl.monitored_paths.should include(to_p('b/c/y.z'))
58
+ end
59
+
60
+ test "doesn't fetch unmonitored paths" do
61
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w(
62
+ a
63
+ b/x.z
64
+ b/c
65
+ b/c/y.z
66
+ ))
67
+ @script.watch('.\.z') { :x }
68
+
69
+ contrl = Controller.new(@script)
70
+ contrl.monitored_paths.should exclude(to_p('a'))
71
+ contrl.monitored_paths.should exclude(to_p('b/c'))
72
+ contrl.monitored_paths.should exclude(to_p('p/q.z'))
73
+ end
74
+
75
+ test "monitored paths include script" do
76
+ Dir.expects(:[]).at_least_once.with('**/*').returns(%w( a ))
77
+ Script.any_instance.stubs(:parse!)
78
+
79
+ path = to_p('some/file')
80
+ script = Script.new(path)
81
+ contrl = Controller.new(script)
82
+ contrl.monitored_paths.should include(path)
83
+ end
84
+
85
+ ## on update
86
+
87
+ test "calls action for path" do
88
+ path = to_p('abc')
89
+ @script.expects(:call_action_for).with(path, :modified).returns(nil)
90
+
91
+ @controller.update('abc', :modified)
92
+ end
93
+
94
+ test "parses script on script file update" do
95
+ path = to_p('abc')
96
+ @script.stubs(:path).returns(path)
97
+ @script.expects(:parse!)
98
+
99
+ @controller.update('abc')
100
+ end
101
+
102
+ test "refreshes handler on script file update" do
103
+ path = to_p('abc')
104
+ @script.stubs(:path).returns(path)
105
+ @controller.stubs(:monitored_paths).returns %w( foo bar )
106
+
107
+ @handler.expects(:refresh).with %w( foo bar )
108
+ @controller.update(path)
109
+ end
110
+
111
+ test "refreshes handler on script action exception" do
112
+ path = to_p('abc')
113
+ @script.stubs(:path).returns(path)
114
+
115
+ file = to_p('012')
116
+ @script.expects(:call_action_for).with(file,nil).raises(Wake::Refresh)
117
+
118
+ @controller.stubs(:monitored_paths).returns %w( foo bar )
119
+
120
+ @handler.expects(:refresh).with %w( foo bar )
121
+
122
+ @controller.update(file)
123
+ end
124
+
125
+ test "exits gracefully when Interrupted" do
126
+ @handler.stubs(:listen).raises(Interrupt)
127
+ @controller.run
128
+ end
129
+ end
130
+
@@ -0,0 +1,60 @@
1
+ require 'pathname'
2
+ require 'tempfile'
3
+ require 'test/unit'
4
+
5
+ require 'matchy'
6
+ require 'mocha'
7
+ require 'every'
8
+ require 'pending'
9
+ begin
10
+ require 'redgreen'
11
+ require 'phocus'
12
+ require 'ruby-debug'
13
+ rescue LoadError, RuntimeError
14
+ end
15
+
16
+ root = Pathname(__FILE__).dirname.parent.expand_path
17
+ $:.unshift(root.join('lib').to_s).uniq!
18
+
19
+ require 'wake'
20
+
21
+ class Test::Unit::TestCase
22
+ class << self
23
+ def test(name, &block)
24
+ name = :"test_#{name.gsub(/\s/,'_')}"
25
+ define_method(name, &block)
26
+ end
27
+ alias :should :test
28
+
29
+ # noop
30
+ def xtest(*args) end
31
+ end
32
+ end
33
+
34
+ # taken from minitest/unit.rb
35
+ # (with modifications)
36
+ def capture_io
37
+ require 'stringio'
38
+
39
+ orig_stdout, orig_stderr = $stdout, $stderr
40
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
41
+ $stdout, $stderr = captured_stdout, captured_stderr
42
+
43
+ yield
44
+
45
+ return Struct.new(:stdout, :stderr).new(
46
+ captured_stdout.string,
47
+ captured_stderr.string
48
+ )
49
+ ensure
50
+ $stdout = orig_stdout
51
+ $stderr = orig_stderr
52
+ end
53
+
54
+ begin
55
+ require "wake/event_handlers/rev"
56
+ HAVE_REV = true
57
+ rescue LoadError
58
+ HAVE_REV = false
59
+ end
60
+
@@ -0,0 +1,124 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestScript < Test::Unit::TestCase
4
+ include Wake
5
+
6
+ def setup
7
+ tmpfile = Tempfile.new('foo')
8
+ @script = Script.new( Pathname.new( tmpfile.path ) )
9
+ end
10
+
11
+ ## external api
12
+
13
+ test "watch" do
14
+ @script.watch('pattern')
15
+ @script.watch('pattern', :event_type)
16
+ @script.watch('pattern') { nil }
17
+ end
18
+
19
+ test "default action" do
20
+ @script.default_action { nil }
21
+ end
22
+
23
+ ## functionality
24
+
25
+ test "rule object" do
26
+ rule = @script.watch('pattern', :modified) { nil }
27
+ rule.pattern.should be('pattern')
28
+ rule.event_types[0].should be(:modified)
29
+ rule.action.call.should be(nil)
30
+ end
31
+
32
+ test "default event type" do
33
+ rule = @script.watch('pattern') { nil }
34
+ rule.event_types[0].should be(:modified)
35
+ end
36
+
37
+ test "finds action for path" do
38
+ @script.watch('abc') { :x }
39
+ @script.watch('def') { :y }
40
+ @script.call_action_for('abc').should be(:x)
41
+ end
42
+
43
+ test "finds action for path with event type" do
44
+ @script.watch('abc', :accessed) { :x }
45
+ @script.watch('abc', :modified) { :y }
46
+ @script.call_action_for('abc', :accessed).should be(:x)
47
+ end
48
+
49
+ test "finds action for path with any event type" do
50
+ @script.watch('abc', nil) { :x }
51
+ @script.watch('abc', :modified) { :y }
52
+ @script.call_action_for('abc', :accessed).should be(:x)
53
+ end
54
+
55
+ test "no action for path" do
56
+ @script.watch('abc', :accessed) { :x }
57
+ @script.call_action_for('abc', :modified).should be(nil)
58
+ end
59
+
60
+ test "collects patterns" do
61
+ @script.watch('abc')
62
+ @script.watch('def')
63
+ @script.patterns.should include('abc')
64
+ @script.patterns.should include('def')
65
+ end
66
+
67
+ test "parses script file" do
68
+ file = Pathname( Tempfile.open('bar').path )
69
+ file.open('w') {|f| f.write <<-STR }
70
+ watch( 'abc' ) { :x }
71
+ STR
72
+ script = Script.new(file)
73
+ script.parse!
74
+ script.call_action_for('abc').should be(:x)
75
+ end
76
+
77
+ test "resets state" do
78
+ @script.default_action { 'x' }
79
+ @script.watch('foo') { 'bar' }
80
+ @script.send(:reset)
81
+ @script.instance_variable_get(:@default_action).call.should be(nil)
82
+ @script.instance_variable_get(:@rules).should be([])
83
+ end
84
+
85
+ test "resets state on parse" do
86
+ @script.stubs(:instance_eval)
87
+ @script.expects(:reset)
88
+ @script.parse!
89
+ end
90
+
91
+ test "actions receive a MatchData object" do
92
+ @script.watch('de(.)') {|m| [m[0], m[1]] }
93
+ @script.call_action_for('def').should be(%w( def f ))
94
+ end
95
+
96
+ test "rule's default action" do
97
+ @script.watch('abc')
98
+ @script.call_action_for('abc').should be(nil)
99
+ @script.default_action { :x }
100
+
101
+ @script.watch('def')
102
+ @script.call_action_for('def').should be(:x)
103
+ end
104
+
105
+ test "file path" do
106
+ Script.any_instance.stubs(:parse!)
107
+ path = Pathname('some/file').expand_path
108
+ script = Script.new(path)
109
+ script.path.should be(path)
110
+ end
111
+
112
+ test "later rules take precedence" do
113
+ @script.watch('a/(.*)\.x') { :x }
114
+ @script.watch('a/b/(.*)\.x') { :y }
115
+
116
+ @script.call_action_for('a/b/c.x').should be(:y)
117
+ end
118
+
119
+ test "rule patterns match against paths relative to pwd" do
120
+ @script.watch('^abc') { :x }
121
+ path = Pathname(Dir.pwd) + 'abc'
122
+ @script.call_action_for(path).should be(:x)
123
+ end
124
+ end