paradeiser 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +8 -0
- data/Gemfile +6 -0
- data/Guardfile +17 -0
- data/README.md +76 -187
- data/Rakefile +12 -1
- data/TODO.md +62 -0
- data/VISION.md +474 -0
- data/bin/pom +60 -0
- data/doc/Paradeiser::Pomodoro_status.svg +50 -0
- data/lib/paradeiser.rb +25 -2
- data/lib/paradeiser/controllers/controller.rb +30 -0
- data/lib/paradeiser/controllers/paradeiser_controller.rb +10 -0
- data/lib/paradeiser/controllers/pomodori_controller.rb +38 -0
- data/lib/paradeiser/errors.rb +31 -0
- data/lib/paradeiser/executor.rb +15 -0
- data/lib/paradeiser/models/hook.rb +26 -0
- data/lib/paradeiser/models/job.rb +25 -0
- data/lib/paradeiser/models/pomodoro.rb +58 -0
- data/lib/paradeiser/models/repository.rb +57 -0
- data/lib/paradeiser/models/scheduler.rb +43 -0
- data/lib/paradeiser/refinements.rb +5 -0
- data/lib/paradeiser/router.rb +29 -0
- data/lib/paradeiser/version.rb +1 -1
- data/lib/paradeiser/view.rb +21 -0
- data/lib/paradeiser/views/paradeiser/init.erb +1 -0
- data/lib/paradeiser/views/pomodori/finish.erb +1 -0
- data/lib/paradeiser/views/pomodori/report.erb +5 -0
- data/lib/paradeiser/views/pomodori/start.erb +1 -0
- data/lib/paradeiser/views/pomodori/status.erb +9 -0
- data/paradeiser.gemspec +21 -4
- data/templates/linux/hooks/after-finish +10 -0
- data/templates/linux/hooks/after-start +7 -0
- data/templates/mac/hooks/after-finish +10 -0
- data/templates/mac/hooks/after-start +7 -0
- data/test/helper.rb +24 -0
- data/test/integration/test_pom.rb +17 -0
- data/test/lib/assertions.rb +10 -0
- data/test/lib/at_mock.rb +6 -0
- data/test/lib/options_mock.rb +7 -0
- data/test/lib/pomodoro_mock.rb +11 -0
- data/test/lib/process_status_mock.rb +2 -0
- data/test/lib/pstore_mock.rb +16 -0
- data/test/templates/hooks/pre-finish +1 -0
- data/test/unit/test_paradeiser_controller.rb +88 -0
- data/test/unit/test_pomodori_controller.rb +103 -0
- data/test/unit/test_pomodori_view.rb +78 -0
- data/test/unit/test_pomodoro.rb +100 -0
- data/test/unit/test_pomodoro_hooks.rb +83 -0
- data/test/unit/test_repository.rb +127 -0
- data/test/unit/test_router.rb +36 -0
- data/test/unit/test_scheduler.rb +44 -0
- metadata +244 -13
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestPomodoriView < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
@pom = Pomodoro.new
|
6
|
+
@pom.id = 1
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_status_idle
|
10
|
+
out, err = render(:status)
|
11
|
+
assert_match(/^Current state is idle.$/m, out)
|
12
|
+
assert_empty(err)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_status_active
|
16
|
+
start!
|
17
|
+
out, err = render(:status)
|
18
|
+
assert_match(/^Pomodoro #1 is active for another \d{1,2} minutes \(started at .*\)\.$/m, out)
|
19
|
+
assert_empty(err)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_status_finished
|
23
|
+
start!
|
24
|
+
finish!
|
25
|
+
out, err = render(:status)
|
26
|
+
assert_match(/^No active pomodoro. Last one was finished at .*\.$/m, out)
|
27
|
+
assert_empty(err)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_report_empty
|
31
|
+
@pom = []
|
32
|
+
out, err = render(:report)
|
33
|
+
assert_equal(1, out.lines.size)
|
34
|
+
assert_match(/^ID \| Status \| Started \| Ended$/m, out.lines.first)
|
35
|
+
assert_empty(err)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_report_one_active
|
39
|
+
start!
|
40
|
+
@pom = [@pom]
|
41
|
+
out, err = render(:report)
|
42
|
+
assert_equal(2, out.lines.size)
|
43
|
+
assert_match(/^ID \| Status \| Started \| Ended$/m, out.lines[0])
|
44
|
+
assert_match(/^1 \| active \| \d{1,2}:\d{1,2} \| $/m, out.lines[1])
|
45
|
+
assert_empty(err)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_report_one_finished
|
49
|
+
start!
|
50
|
+
finish!
|
51
|
+
@pom = [@pom]
|
52
|
+
out, err = render(:report)
|
53
|
+
assert_equal(2, out.lines.size)
|
54
|
+
assert_match(/^ID \| Status \| Started \| Ended$/m, out.lines[0])
|
55
|
+
assert_match(/^1 \| finished \| \d{1,2}:\d{1,2} \| \d{1,2}:\d{1,2}$/m, out.lines[1])
|
56
|
+
assert_empty(err)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_start
|
60
|
+
out, err = render(:start)
|
61
|
+
assert_match(/^Starting pomodoro #1\.$/m, out)
|
62
|
+
assert_empty(err)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_finish
|
66
|
+
start!
|
67
|
+
out, err = render(:finish)
|
68
|
+
assert_match(/^Finished pomodoro #1 after .* minutes\.$/m, out)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def render(method)
|
74
|
+
capture_io do
|
75
|
+
View.new('Pomodori', method).render(binding)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestPomodoro < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
@pom = Pomodoro.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_virgin
|
9
|
+
assert_equal(:idle, @pom.status_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_finish_idle
|
13
|
+
assert_raises StateMachine::InvalidTransition do
|
14
|
+
finish!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_finish
|
19
|
+
start!
|
20
|
+
assert_equal(:active, @pom.status_name)
|
21
|
+
|
22
|
+
now = srand
|
23
|
+
|
24
|
+
Time.stub :now, Time.at(now) do
|
25
|
+
finish!
|
26
|
+
end
|
27
|
+
|
28
|
+
assert_equal(:finished, @pom.status_name)
|
29
|
+
assert_equal(now, @pom.finished_at.to_i)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_duration_idle
|
33
|
+
assert_equal(0, @pom.duration)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_duration_started
|
37
|
+
now = srand
|
38
|
+
|
39
|
+
Time.stub :now, Time.at(now) do
|
40
|
+
start!
|
41
|
+
end
|
42
|
+
|
43
|
+
later = now + rand(42)
|
44
|
+
|
45
|
+
Time.stub :now, Time.at(later) do
|
46
|
+
assert_equal(later - now, @pom.duration)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_duration_finished
|
51
|
+
now = srand
|
52
|
+
|
53
|
+
Time.stub :now, Time.at(now) do
|
54
|
+
start!
|
55
|
+
end
|
56
|
+
|
57
|
+
later = now + rand(42)
|
58
|
+
|
59
|
+
Time.stub :now, Time.at(later) do
|
60
|
+
finish!
|
61
|
+
end
|
62
|
+
|
63
|
+
assert_equal(later - now, @pom.duration)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_finish_finished
|
67
|
+
start!
|
68
|
+
finish!
|
69
|
+
assert_raises StateMachine::InvalidTransition do
|
70
|
+
finish!
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_start
|
75
|
+
now = srand
|
76
|
+
|
77
|
+
Time.stub :now, Time.at(now) do
|
78
|
+
start!
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal(:active, @pom.status_name)
|
82
|
+
assert_equal(now, @pom.started_at.to_i)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_remaining
|
86
|
+
now = srand
|
87
|
+
|
88
|
+
Time.stub :now, Time.at(now) do
|
89
|
+
start!
|
90
|
+
assert_equal(Pomodoro::LENGTH_SECONDS, @pom.remaining)
|
91
|
+
end
|
92
|
+
|
93
|
+
delta = 600
|
94
|
+
later = now + delta
|
95
|
+
|
96
|
+
Time.stub :now, Time.at(later) do
|
97
|
+
assert_equal(Pomodoro::LENGTH_SECONDS - delta, @pom.remaining)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
class TestPomodoroHooks < MiniTest::Test
|
5
|
+
def setup
|
6
|
+
@orig_pom_dir = ENV['POM_DIR']
|
7
|
+
ENV['POM_DIR'] = Dir.mktmpdir
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
FileUtils.rm_rf(Paradeiser.pom_dir)
|
12
|
+
ENV['POM_DIR'] = @orig_pom_dir
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_before_finish_success
|
16
|
+
hook_name = 'before-finish'
|
17
|
+
|
18
|
+
pom = Pomodoro.new
|
19
|
+
pom.id = SecureRandom.random_number(1000)
|
20
|
+
pom.start
|
21
|
+
token_file = create_hook(hook_name)
|
22
|
+
refute_path_exists(token_file, "Token file must not exist before #{hook_name} hook is executed")
|
23
|
+
pom.finish
|
24
|
+
assert_path_exists(token_file, "#{hook_name} hook should have created a token file")
|
25
|
+
assert_equal(:finished, pom.status_name)
|
26
|
+
assert_equal("Pomodoro #{pom.id} started #{pom.started_at.strftime('%H:%M')}", File.read(token_file).chomp)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_before_finish_error
|
30
|
+
hook_name = 'before-finish'
|
31
|
+
|
32
|
+
pom = Pomodoro.new
|
33
|
+
pom.id = SecureRandom.random_number(1000)
|
34
|
+
pom.start
|
35
|
+
token_file = create_hook(hook_name, false)
|
36
|
+
refute_path_exists(token_file, "Token file must not exist before #{hook_name} hook is executed")
|
37
|
+
|
38
|
+
assert_raises HookFailedError do
|
39
|
+
pom.finish
|
40
|
+
end
|
41
|
+
|
42
|
+
refute_path_exists(token_file, "#{hook_name} hook should have created a token file")
|
43
|
+
assert_equal(:active, pom.status_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def create_hook(name, hook_succeeds = true)
|
49
|
+
token_file = File.join(Dir.tmpdir, SecureRandom.uuid)
|
50
|
+
|
51
|
+
hooks_dir = Paradeiser.hooks_dir
|
52
|
+
FileUtils.mkdir(hooks_dir)
|
53
|
+
|
54
|
+
hook_file = File.join(hooks_dir, name)
|
55
|
+
|
56
|
+
File.open(hook_file, 'w') do |f|
|
57
|
+
if hook_succeeds
|
58
|
+
f.write(hook_contents_success(token_file))
|
59
|
+
else
|
60
|
+
f.write(hook_contents_failure)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
File.chmod(0700, hook_file)
|
65
|
+
|
66
|
+
assert(File.exist?(hook_file))
|
67
|
+
token_file
|
68
|
+
end
|
69
|
+
|
70
|
+
def hook_contents_success(token_file)
|
71
|
+
hook_contents =<<"EOF"
|
72
|
+
#!/bin/sh
|
73
|
+
echo "Pomodoro $POM_ID started $POM_STARTED_AT" > #{token_file}
|
74
|
+
EOF
|
75
|
+
end
|
76
|
+
|
77
|
+
def hook_contents_failure
|
78
|
+
hook_contents =<<"EOF"
|
79
|
+
#!/bin/sh
|
80
|
+
exit 1
|
81
|
+
EOF
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestRepository < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
@backend = PStoreMock.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_save_idle
|
9
|
+
pom = Pomodoro.new
|
10
|
+
|
11
|
+
assert_raises IllegalStatusError do
|
12
|
+
invoke(:save, pom)
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_equal(0, @backend.size)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_save_active
|
19
|
+
pom = Pomodoro.new
|
20
|
+
start!(pom)
|
21
|
+
|
22
|
+
invoke(:save, pom)
|
23
|
+
|
24
|
+
assert_equal(1, @backend.size)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_save_second_active
|
28
|
+
pom1 = Pomodoro.new
|
29
|
+
start!(pom1)
|
30
|
+
|
31
|
+
pom2 = Pomodoro.new
|
32
|
+
start!(pom2)
|
33
|
+
|
34
|
+
invoke(:save, pom1)
|
35
|
+
|
36
|
+
assert_raises SingletonError do
|
37
|
+
invoke(:save, pom2)
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_equal(1, @backend.size)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_save_finished
|
44
|
+
pom = Pomodoro.new
|
45
|
+
start!(pom)
|
46
|
+
finish!(pom)
|
47
|
+
|
48
|
+
invoke(:save, pom)
|
49
|
+
|
50
|
+
assert_equal(1, @backend.size)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_save_active_finish_save
|
54
|
+
pom = Pomodoro.new
|
55
|
+
start!(pom)
|
56
|
+
|
57
|
+
invoke(:save, pom)
|
58
|
+
finish!(pom)
|
59
|
+
invoke(:save, pom)
|
60
|
+
|
61
|
+
assert_equal(1, @backend.size)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_all
|
65
|
+
@backend[:foo] = 'bar'
|
66
|
+
assert_equal(1, @backend.size)
|
67
|
+
|
68
|
+
all = invoke(:all)
|
69
|
+
|
70
|
+
assert_equal(1, all.size)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_any
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_find
|
77
|
+
@backend[:foo] = PomodoroMock.new(:length => 3)
|
78
|
+
@backend[:bar] = PomodoroMock.new(:length => 3)
|
79
|
+
@backend[:baz] = PomodoroMock.new(:length => 2)
|
80
|
+
assert_equal(3, @backend.size)
|
81
|
+
|
82
|
+
all = invoke(:find){|pom| pom.length == 3}
|
83
|
+
|
84
|
+
assert_equal(2, all.size)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_active
|
88
|
+
@backend[:foo] = PomodoroMock.new(:active => false)
|
89
|
+
@backend[:bar] = PomodoroMock.new(:active => true)
|
90
|
+
@backend[:baz] = PomodoroMock.new(:active => false)
|
91
|
+
|
92
|
+
active = invoke(:active)
|
93
|
+
assert_equal(@backend[:bar], active)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_active_true
|
97
|
+
@backend[:foo] = PomodoroMock.new(:active => false)
|
98
|
+
@backend[:bar] = PomodoroMock.new(:active => true)
|
99
|
+
@backend[:baz] = PomodoroMock.new(:active => false)
|
100
|
+
|
101
|
+
assert(invoke(:active?))
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_active_false
|
105
|
+
@backend[:foo] = PomodoroMock.new(:active => false)
|
106
|
+
@backend[:bar] = PomodoroMock.new(:active => false)
|
107
|
+
@backend[:baz] = PomodoroMock.new(:active => false)
|
108
|
+
|
109
|
+
refute(invoke(:active?))
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_corrupted_repo
|
113
|
+
@backend[:foo] = PomodoroMock.new(:active => true)
|
114
|
+
@backend[:bar] = PomodoroMock.new(:active => true)
|
115
|
+
|
116
|
+
assert_raises SingletonError do
|
117
|
+
invoke(:active?)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
private
|
121
|
+
|
122
|
+
def invoke(method, *args, &blk)
|
123
|
+
Repository.stub :backend, @backend do
|
124
|
+
Repository.send(method, *args, &blk)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'fakefs/safe'
|
3
|
+
|
4
|
+
class CommandMock < Struct.new(:name)
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestRouter < MiniTest::Test
|
8
|
+
def setup
|
9
|
+
FakeFS.activate!
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
FakeFS.deactivate!
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_init
|
17
|
+
refute(Dir.exists?(Paradeiser.pom_dir), "Expect #{Paradeiser.pom_dir} to not exist yet")
|
18
|
+
|
19
|
+
block = Router.new.dispatch(CommandMock.new(:init))
|
20
|
+
refute_nil(block)
|
21
|
+
|
22
|
+
refute(Dir.exists?(Paradeiser.pom_dir), "Expect #{Paradeiser.pom_dir} to not exist yet")
|
23
|
+
|
24
|
+
# fake the view
|
25
|
+
dirname = File.join(File.dirname(__FILE__), '..', '..', 'lib', 'paradeiser', 'views', 'paradeiser')
|
26
|
+
FileUtils.mkdir_p(dirname)
|
27
|
+
view = File.join(dirname, 'init.erb')
|
28
|
+
FileUtils.touch(view)
|
29
|
+
|
30
|
+
begin
|
31
|
+
block.call(nil, OptionsMock.new(:trace => true, :verbose => false))
|
32
|
+
ensure
|
33
|
+
FileUtils.rm_r(Paradeiser.pom_dir, :force => true)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestScheduler < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
if Scheduler.list.any?
|
6
|
+
@do_not_clear = true
|
7
|
+
raise "The at queue 't' is not empty. Clean it up before running this test again."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
Scheduler.clear unless @do_not_clear
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_add
|
16
|
+
result = Scheduler.list
|
17
|
+
assert_equal(0, result.size)
|
18
|
+
|
19
|
+
job = Scheduler.add(:finish, 42)
|
20
|
+
refute_nil(job)
|
21
|
+
refute_nil(job.id)
|
22
|
+
assert(0 < job.id.to_i)
|
23
|
+
|
24
|
+
list = Scheduler.list
|
25
|
+
assert_equal(1, list.size)
|
26
|
+
assert_equal(job, list.first)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_clear
|
30
|
+
n = 3
|
31
|
+
|
32
|
+
n.times.each do |spec|
|
33
|
+
Scheduler.add(:finish, 43)
|
34
|
+
end
|
35
|
+
|
36
|
+
result = Scheduler.list
|
37
|
+
assert_equal(n, result.size)
|
38
|
+
|
39
|
+
Scheduler.clear
|
40
|
+
|
41
|
+
result = Scheduler.list
|
42
|
+
assert_equal(0, result.size)
|
43
|
+
end
|
44
|
+
end
|