paradeiser 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Guardfile +1 -0
  4. data/README.md +98 -6
  5. data/TODO.md +22 -6
  6. data/VISION.md +171 -26
  7. data/bin/par +20 -4
  8. data/lib/paradeiser/controllers/breaks_controller.rb +0 -1
  9. data/lib/paradeiser/controllers/controller.rb +15 -1
  10. data/lib/paradeiser/controllers/paradeiser_controller.rb +23 -1
  11. data/lib/paradeiser/controllers/pomodori_controller.rb +23 -1
  12. data/lib/paradeiser/errors.rb +6 -0
  13. data/lib/paradeiser/executor.rb +1 -1
  14. data/lib/paradeiser/initializers/inflections.rb +3 -0
  15. data/lib/paradeiser/models/break.rb +1 -0
  16. data/lib/paradeiser/models/pomodoro.rb +13 -1
  17. data/lib/paradeiser/models/repository.rb +11 -1
  18. data/lib/paradeiser/models/scheduled.rb +7 -1
  19. data/lib/paradeiser/refinements/pluralize.rb +10 -0
  20. data/lib/paradeiser/router.rb +0 -2
  21. data/lib/paradeiser/version.rb +1 -1
  22. data/lib/paradeiser/view.rb +1 -1
  23. data/lib/paradeiser/views/breaks/finish.erb +1 -0
  24. data/lib/paradeiser/views/breaks/start.erb +1 -0
  25. data/lib/paradeiser/views/paradeiser/init.erb +1 -1
  26. data/lib/paradeiser/views/paradeiser/report.erb +10 -4
  27. data/lib/paradeiser/views/paradeiser/status.erb +2 -1
  28. data/lib/paradeiser/views/pomodori/annotate.erb +1 -0
  29. data/lib/paradeiser/views/pomodori/cancel.erb +1 -0
  30. data/lib/paradeiser/views/pomodori/interrupt.erb +1 -0
  31. data/lib/paradeiser/views/pomodori/log.erb +1 -0
  32. data/lib/paradeiser/views/pomodori/start.erb +1 -1
  33. data/paradeiser.gemspec +2 -0
  34. data/test/bin/notify-send +1 -0
  35. data/test/helper.rb +7 -24
  36. data/test/integration/test_annotate.rb +19 -0
  37. data/test/integration/test_finish.rb +9 -0
  38. data/test/integration/test_interrupt.rb +9 -0
  39. data/test/integration/test_log.rb +12 -0
  40. data/test/integration/test_no_args.rb +7 -0
  41. data/test/integration/test_start.rb +7 -0
  42. data/test/integration/test_status.rb +10 -0
  43. data/test/integration/test_unknown.rb +7 -0
  44. data/test/lib/at_mock.rb +1 -1
  45. data/test/lib/controller_test.rb +25 -0
  46. data/test/lib/integration_test.rb +45 -0
  47. data/test/lib/paradeiser_controller_test.rb +7 -0
  48. data/test/lib/view_test.rb +12 -0
  49. data/test/unit/test_break.rb +7 -44
  50. data/test/unit/test_break_view.rb +22 -0
  51. data/test/unit/test_breaks_controller.rb +66 -0
  52. data/test/unit/test_paradeiser_controller_export.rb +107 -0
  53. data/test/unit/test_paradeiser_controller_report.rb +73 -26
  54. data/test/unit/test_paradeiser_controller_status.rb +42 -24
  55. data/test/unit/test_paradeiser_view_init.rb +7 -0
  56. data/test/unit/test_paradeiser_view_report.rb +132 -0
  57. data/test/unit/test_paradeiser_view_status.rb +17 -0
  58. data/test/unit/test_pomodori_controller.rb +241 -33
  59. data/test/unit/test_pomodori_view.rb +26 -13
  60. data/test/unit/test_pomodoro.rb +23 -81
  61. data/test/unit/test_pomodoro_hooks.rb +12 -25
  62. data/test/unit/test_repository.rb +5 -21
  63. data/test/unit/test_scheduler.rb +1 -1
  64. metadata +61 -8
  65. data/test/integration/test_par.rb +0 -17
  66. data/test/unit/test_break_controller.rb +0 -56
  67. data/test/unit/test_paradeiser_view.rb +0 -66
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ class TestAnnotateCommand < Paradeiser::IntegrationTest
4
+ def test_annotate_no_previous
5
+ refute_command('annotate')
6
+ end
7
+
8
+ def test_annotate_active
9
+ assert_command('start')
10
+ assert_command('annotate', 0, name.split('_'))
11
+ end
12
+
13
+ def test_annotate_second_last_successful
14
+ assert_command('start')
15
+ assert_command('finish')
16
+ assert_command('break')
17
+ assert_command('annotate', 0, name.split('_'))
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require 'helper'
2
+
3
+ class TestFinishCommand < Paradeiser::IntegrationTest
4
+ def test_finish
5
+ refute_command('finish')
6
+ assert_command('start')
7
+ assert_command('finish')
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'helper'
2
+
3
+ class TestInterruptCommand < Paradeiser::IntegrationTest
4
+ def test_interrupt
5
+ refute_command('interrupt')
6
+ assert_command('start')
7
+ assert_command('interrupt')
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require 'helper'
2
+
3
+ class TestLogCommand < Paradeiser::IntegrationTest
4
+ def test_log_inactive
5
+ assert_command('log', 0, name.split('_'))
6
+ end
7
+
8
+ def test_log_active
9
+ assert_command('start')
10
+ assert_command('log', 0, name.split('_'))
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestNoArgsCommand < Paradeiser::IntegrationTest
4
+ def test_no_args
5
+ assert_command('')
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestStartCommand < Paradeiser::IntegrationTest
4
+ def test_start
5
+ assert_command('start')
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ class TestStatusCommand < Paradeiser::IntegrationTest
4
+ def test_status
5
+ assert_command('status', 255) # not initialized
6
+ assert_command('start')
7
+ out = assert_command('status')
8
+ refute_empty(out, "Expected 'status' to produce an non-empty output")
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestUnknownCommand < Paradeiser::IntegrationTest
4
+ def test_unknown
5
+ refute_command('unknown')
6
+ end
7
+ end
@@ -1,6 +1,6 @@
1
1
  # Include this module in order to use another queue for at commands
2
2
  module Executor
3
3
  def queue
4
- 't'
4
+ ENV['PAR_AT_QUEUE'] || 't'
5
5
  end
6
6
  end
@@ -0,0 +1,25 @@
1
+ module Paradeiser
2
+ class ControllerTest < MiniTest::Test
3
+ def invoke(method, args = nil, options = nil, *attributes)
4
+ controller = Paradeiser.const_get("#{model.pluralize.capitalize}Controller".to_sym).new(method)
5
+
6
+ stdout, stderr = Repository.stub :backend, @backend do
7
+ Scheduler.stub(:add, nil) do
8
+ Scheduler.stub(:clear, nil) do
9
+ capture_io do
10
+ controller.call(Array(args), options)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ result = Hash[attributes.map do |e|
17
+ [e.split('@').last.to_sym, controller.get_binding.eval(e)]
18
+ end]
19
+
20
+ result[:stdout] = stdout
21
+ result[:stderr] = stderr
22
+ result
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,45 @@
1
+ require 'helper'
2
+
3
+ module Paradeiser
4
+ #
5
+ # We put all integration tests into separate files so we only run one at a
6
+ # time after a change. These tests are expensive to run.
7
+ #
8
+ class IntegrationTest < MiniTest::Test
9
+ PAR = 'bin/par'
10
+ include Executor
11
+
12
+ def setup
13
+ if Scheduler.list.any?
14
+ @do_not_clear = true
15
+ raise "The at queue '#{queue}' is not empty. Clean it up before running this test again."
16
+ end
17
+
18
+ @orig_PAR_DIR = ENV['PAR_DIR']
19
+ ENV['PAR_DIR'] = Dir.mktmpdir
20
+ ENV['PAR_AT_QUEUE'] = 'i'
21
+ assert_command('init')
22
+ end
23
+
24
+ def teardown
25
+ FileUtils.rm_rf(Paradeiser.par_dir)
26
+ ENV['PAR_DIR'] = @orig_PAR_DIR
27
+ Scheduler.clear unless @do_not_clear
28
+ raise "The at queue #{queue} is not empty. Clean it up before running this test again." if Scheduler.list.any?
29
+ ENV.delete('PAR_AT_QUEUE')
30
+ end
31
+
32
+ def assert_command(cmd, expected_status = 0, *args)
33
+ out, err, status = Open3.capture3("#{PAR} #{cmd} #{Shellwords.join(args)}")
34
+ assert_equal(expected_status, status.exitstatus, "Expected exit status to be #{expected_status}, but it was #{status.exitstatus}. STDERR is: '#{err}'")
35
+ assert_empty(err)
36
+ out
37
+ end
38
+
39
+ def refute_command(cmd, expected_status = 1, *args)
40
+ out, err, status = Open3.capture3("#{PAR} #{cmd}")
41
+ assert_equal(expected_status, status.exitstatus, "Expected exit status to be #{expected_status}, but it was #{status.exitstatus}.")
42
+ [out, err]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module Paradeiser
2
+ class ParadeiserControllerTest < ControllerTest
3
+ def model
4
+ 'paradeiser'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class ViewTest < MiniTest::Test
2
+ def render(method)
3
+ View.new(model.pluralize, method).render(binding)
4
+ end
5
+ end
6
+
7
+ class ParadeiserViewTest < ViewTest
8
+ protected
9
+ def model
10
+ 'Paradeiser'
11
+ end
12
+ end
@@ -2,26 +2,14 @@ require 'helper'
2
2
 
3
3
  class TestBreak < MiniTest::Test
4
4
  def setup
5
- @break = Break.new
5
+ @break = produce(Break)
6
6
  end
7
7
 
8
- def test_virgin
9
- assert_equal(:idle, @break.status_name)
10
- end
11
-
12
- def test_break
13
- start!
8
+ def test_new
14
9
  assert_equal(:active, @break.status_name)
15
10
  end
16
11
 
17
- def test_finish_idle
18
- assert_raises StateMachine::InvalidTransition do
19
- finish!
20
- end
21
- end
22
-
23
12
  def test_finish_break
24
- start!
25
13
  assert_equal(:active, @break.status_name)
26
14
 
27
15
  now = srand
@@ -38,43 +26,25 @@ class TestBreak < MiniTest::Test
38
26
  assert_equal(5 * 60, @break.length)
39
27
  end
40
28
 
41
-
42
- def test_duration_idle
43
- assert_equal(0, @break.duration)
44
- end
45
-
46
29
  def test_duration
47
- now = srand
48
-
49
- Time.stub :now, Time.at(now) do
50
- start!
51
- end
52
-
53
- later = now + rand(42)
30
+ later = @started + rand(42)
54
31
 
55
32
  Time.stub :now, Time.at(later) do
56
- assert_equal(later - now, @break.duration)
33
+ assert_equal(later - @started, @break.duration)
57
34
  end
58
35
  end
59
36
 
60
37
  def test_duration_finished
61
- now = srand
62
-
63
- Time.stub :now, Time.at(now) do
64
- start!
65
- end
66
-
67
- later = now + rand(42)
38
+ later = @started + rand(42)
68
39
 
69
40
  Time.stub :now, Time.at(later) do
70
41
  finish!
71
42
  end
72
43
 
73
- assert_equal(later - now, @break.duration)
44
+ assert_equal(later - @started, @break.duration)
74
45
  end
75
46
 
76
47
  def test_finish_break
77
- start!
78
48
  finish!
79
49
  assert_raises StateMachine::InvalidTransition do
80
50
  finish!
@@ -82,15 +52,8 @@ class TestBreak < MiniTest::Test
82
52
  end
83
53
 
84
54
  def test_remaining
85
- now = srand
86
-
87
- Time.stub :now, Time.at(now) do
88
- start!
89
- assert_equal(@break.length, @break.remaining)
90
- end
91
-
92
55
  delta = 120
93
- later = now + delta
56
+ later = @started + delta
94
57
 
95
58
  Time.stub :now, Time.at(later) do
96
59
  assert_equal(@break.length - delta, @break.remaining)
@@ -0,0 +1,22 @@
1
+ require 'helper'
2
+
3
+ class TestBreakView < ViewTest
4
+ def setup
5
+ @break = produce(Break)
6
+ @break.id = 1
7
+ end
8
+
9
+ def test_start
10
+ assert_match(/^Started a new break \(5 minutes\)\.$/m, render(:start))
11
+ end
12
+
13
+ def test_finish
14
+ assert_match(/^Finished break #1 after .* minutes\.$/m, render(:finish))
15
+ end
16
+
17
+ protected
18
+
19
+ def model
20
+ 'Break'
21
+ end
22
+ end
@@ -0,0 +1,66 @@
1
+ require 'helper'
2
+
3
+ class TestBreaksController < ControllerTest
4
+ def setup
5
+ @backend = PStoreMock.new
6
+ end
7
+
8
+ def model
9
+ 'break'
10
+ end
11
+
12
+ def test_break
13
+ attrs = invoke(:start, nil, nil, '@break', 'exitstatus', 'has_output')
14
+ assert_equal(:active, attrs[:break].status_name)
15
+ assert_equal(false, attrs[:has_output])
16
+ assert_empty(attrs[:stdout])
17
+ assert_empty(attrs[:stderr])
18
+ assert_equal(1, @backend.size)
19
+ end
20
+
21
+ def test_break_verbose
22
+ attrs = invoke(:start, nil, OpenStruct.new(:verbose => true), '@break', 'exitstatus', 'has_output')
23
+ assert_equal(:active, attrs[:break].status_name)
24
+ assert_equal(false, attrs[:has_output])
25
+ refute_empty(attrs[:stdout])
26
+ assert_empty(attrs[:stderr])
27
+ assert_equal(1, @backend.size)
28
+ end
29
+
30
+ def test_break_active
31
+ invoke(:start)
32
+ assert_equal(1, @backend.size)
33
+
34
+ assert_raises SingletonError do
35
+ invoke(:start)
36
+ end
37
+ assert_equal(1, @backend.size)
38
+ end
39
+
40
+ def test_finish
41
+ invoke(:start)
42
+ attrs = invoke(:finish, nil, nil, '@break', 'exitstatus', 'has_output')
43
+ assert_equal(:finished, attrs[:break].status_name)
44
+ assert_equal(false, attrs[:has_output])
45
+ assert_empty(attrs[:stdout])
46
+ assert_empty(attrs[:stderr])
47
+ assert_equal(1, @backend.size)
48
+ end
49
+
50
+ def test_finish_verbose
51
+ invoke(:start)
52
+ attrs = invoke(:finish, nil, OpenStruct.new(:verbose => true), '@break', 'exitstatus', 'has_output')
53
+ assert_equal(:finished, attrs[:break].status_name)
54
+ assert_equal(false, attrs[:has_output])
55
+ refute_empty(attrs[:stdout])
56
+ assert_empty(attrs[:stderr])
57
+ assert_equal(1, @backend.size)
58
+ end
59
+
60
+ def test_finish_idle
61
+ assert_raises NotActiveError do
62
+ invoke(:finish)
63
+ end
64
+ assert_equal(0, @backend.size)
65
+ end
66
+ end
@@ -0,0 +1,107 @@
1
+ require 'helper'
2
+
3
+ #
4
+ # There is no view for export, so we need to test the entire results here
5
+ #
6
+ class TestParadeiserControllerExport < ParadeiserControllerTest
7
+ def setup
8
+ @backend = PStoreMock.new
9
+ end
10
+
11
+ def test_empty
12
+ attrs = invoke(:export)
13
+ assert_empty(attrs[:stderr])
14
+
15
+ result = JSON.parse(attrs[:stdout])
16
+ assert(result)
17
+ assert_empty(result)
18
+ end
19
+
20
+ def test_pomodoro
21
+ pom = produce(Pomodoro)
22
+ started_at = Time.new(8)
23
+ pom.started_at = started_at
24
+ pom.finish!
25
+ finished_at = Time.new(16)
26
+ pom.finished_at = finished_at
27
+ @backend[:bar] = pom
28
+
29
+ attrs = invoke(:export)
30
+ assert_empty(attrs[:stderr])
31
+ result = JSON.parse(attrs[:stdout])
32
+
33
+ assert(result)
34
+ refute_empty(result)
35
+ assert_equal(1, result.size)
36
+ p = result.first
37
+ assert(p)
38
+
39
+ assert_equal('Pomodoro', p['type'])
40
+ assert_equal(1500, p['length'])
41
+ assert_equal('finished', p['status'])
42
+ assert_equal(started_at.as_json, p['started_at'])
43
+ assert_equal(finished_at.as_json, p['finished_at'])
44
+
45
+ interrupts = p['interrupts']
46
+ assert(interrupts)
47
+ assert_empty(interrupts)
48
+
49
+ annotations = p['annotations']
50
+ assert(annotations)
51
+ assert_empty(annotations)
52
+ end
53
+
54
+ def test_break
55
+ br3ak = produce(Break)
56
+ started_at = Time.new(8)
57
+ br3ak.started_at = started_at
58
+ br3ak.finish!
59
+ finished_at = Time.new(16)
60
+ br3ak.finished_at = finished_at
61
+ @backend[:bar] = br3ak
62
+
63
+ attrs = invoke(:export)
64
+ assert_empty(attrs[:stderr])
65
+ result = JSON.parse(attrs[:stdout])
66
+
67
+ assert(result)
68
+ refute_empty(result)
69
+ assert_equal(1, result.size)
70
+ p = result.first
71
+ assert(p)
72
+
73
+ assert_equal('Break', p['type'])
74
+ assert_equal(300, p['length'])
75
+ assert_equal('finished', p['status'])
76
+ assert_equal(started_at.as_json, p['started_at'])
77
+ assert_equal(finished_at.as_json, p['finished_at'])
78
+
79
+ refute(p['interrupts'])
80
+ refute(p['annotations'])
81
+ end
82
+
83
+ def test_multiple
84
+ br3ak = produce(Break)
85
+ br3ak.started_at = Time.new(8)
86
+ br3ak.finish!
87
+ br3ak.finished_at = Time.new(16)
88
+ @backend[:bar] = br3ak
89
+
90
+ pom = produce(Pomodoro)
91
+ pom.started_at = Time.new(8)
92
+ pom.finish!
93
+ pom.finished_at = Time.new(16)
94
+ @backend[:foo] = pom
95
+
96
+ attrs = invoke(:export)
97
+ assert_empty(attrs[:stderr])
98
+ result = JSON.parse(attrs[:stdout])
99
+
100
+ assert(result)
101
+ refute_empty(result)
102
+ assert_equal(2, result.size)
103
+
104
+ assert_equal('Break', result.first['type'])
105
+ assert_equal('Pomodoro', result.last['type'])
106
+ end
107
+ end