wake 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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