paradeiser 0.2.0 → 0.4.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.
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