achoo 0.4.2 → 0.5
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.
- data/CHANGES +13 -0
- data/README.rdoc +26 -22
- data/lib/achoo/achievo/hour_administration_form.rb +2 -3
- data/lib/achoo/achievo/hour_registration_form.rb +12 -15
- data/lib/achoo/achievo/hour_registration_form_ranged.rb +5 -2
- data/lib/achoo/achievo/lock_month_form.rb +1 -5
- data/lib/achoo/achievo/login_form.rb +3 -3
- data/lib/achoo/app.rb +27 -28
- data/lib/achoo/awake.rb +1 -1
- data/lib/achoo/extensions.rb +4 -0
- data/lib/achoo/ical.rb +6 -2
- data/lib/achoo/plugin/awake.rb +23 -0
- data/lib/achoo/plugin/ical.rb +47 -0
- data/lib/achoo/plugin/vcs.rb +26 -0
- data/lib/achoo/plugin_base.rb +6 -0
- data/lib/achoo/rc_loader.rb +9 -0
- data/lib/achoo/temporal/timespan.rb +3 -3
- data/lib/achoo/term.rb +7 -3
- data/lib/achoo/term/table.rb +5 -6
- data/lib/achoo/ui/commands.rb +12 -12
- data/lib/achoo/ui/date_chooser.rb +1 -1
- data/lib/achoo/ui/exception_handling.rb +1 -1
- data/lib/achoo/ui/register_hours.rb +50 -50
- data/lib/achoo/vcs/git.rb +5 -3
- data/test/acceptance/test_flexi_time.rb +41 -0
- data/test/acceptance/test_lock_month.rb +39 -0
- data/test/acceptance/test_register_hours.rb +161 -0
- data/test/lib/achievo_mock.rb +76 -0
- data/test/lib/achoo_runner.rb +54 -0
- data/test/lib/test_helpers.rb +43 -0
- data/test/unit/test_achievo_date_field.rb +34 -0
- data/test/unit/test_awake.rb +98 -0
- data/test/unit/test_extensions_array.rb +25 -0
- data/test/unit/test_system_cstruct.rb +28 -0
- data/test/unit/test_system_log_entry.rb +31 -0
- data/test/unit/test_term_menu.rb +71 -0
- data/test/unit/test_term_table.rb +52 -0
- data/test/unit/test_timespan.rb +48 -0
- data/test/unit/test_ui_date_chooser.rb +36 -0
- metadata +101 -74
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'test_helpers'
|
2
|
+
|
3
|
+
class TestLockMonth < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include AcceptanceBase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
|
10
|
+
time_registration_html = %q{
|
11
|
+
<html>
|
12
|
+
<head></head>
|
13
|
+
<body>
|
14
|
+
<form name="entryform">
|
15
|
+
|
16
|
+
<input type="hidden" name="action" value="foo">
|
17
|
+
<input type="hidden" name="atkaction" value="bar">
|
18
|
+
|
19
|
+
<select name="activitydate[day]">
|
20
|
+
<option value="1" >Saturday 1</option>
|
21
|
+
<option value="2" >Sunday 2</option>
|
22
|
+
<option value="3" >Monday 3</option>
|
23
|
+
<option value="4" >Tuesday 4</option>
|
24
|
+
<option value="5" >Wednesday 5</option>
|
25
|
+
<option value="6" >Thursday 6</option>
|
26
|
+
<option value="7" >Friday 7</option>
|
27
|
+
<option value="8" >Saturday 8</option>
|
28
|
+
<option value="9" >Sunday 9</option>
|
29
|
+
<option value="10" >Monday 10</option>
|
30
|
+
<option value="11" >Tuesday 11</option>
|
31
|
+
<option value="12" >Wednesday 12</option>
|
32
|
+
<option value="13" >Thursday 13</option>
|
33
|
+
<option value="14" >Friday 14</option>
|
34
|
+
<option value="15" >Saturday 15</option>
|
35
|
+
<option value="16" >Sunday 16</option>
|
36
|
+
<option value="17" >Monday 17</option>
|
37
|
+
<option value="18" >Tuesday 18</option>
|
38
|
+
<option value="19" >Wednesday 19</option>
|
39
|
+
<option value="20" >Thursday 20</option>
|
40
|
+
<option value="21" >Friday 21</option>
|
41
|
+
<option value="22" >Saturday 22</option>
|
42
|
+
<option value="23" >Sunday 23</option>
|
43
|
+
<option value="24" >Monday 24</option>
|
44
|
+
<option value="25" selected>Tuesday 25</option>
|
45
|
+
<option value="26" >Wednesday 26</option>
|
46
|
+
<option value="27" >Thursday 27</option>
|
47
|
+
<option value="28" >Friday 28</option>
|
48
|
+
<option value="29" >Saturday 29</option>
|
49
|
+
<option value="30" >Sunday 30</option>
|
50
|
+
<option value="31" >Monday 31</option>
|
51
|
+
</select>
|
52
|
+
|
53
|
+
<select name="activitydate[month]">
|
54
|
+
<option value="1" >January</option>
|
55
|
+
<option value="2" >February</option>
|
56
|
+
<option value="3" >March</option>
|
57
|
+
<option value="4" >April</option>
|
58
|
+
<option value="5" selected>May</option>
|
59
|
+
<option value="6" >June</option>
|
60
|
+
<option value="7" >July</option>
|
61
|
+
<option value="8" >August</option>
|
62
|
+
<option value="9" >September</option>
|
63
|
+
<option value="10" >October</option>
|
64
|
+
<option value="11" >November</option>
|
65
|
+
<option value="12" >December</option>
|
66
|
+
</select>
|
67
|
+
|
68
|
+
<input type="text" name="activitydate[year]" value="2010">
|
69
|
+
|
70
|
+
<a href="FIX">Select range</a>
|
71
|
+
|
72
|
+
<select name="projectid">
|
73
|
+
<option value="project.id='1'" >foo: Foo</option>
|
74
|
+
<option value="project.id='2'" >bar: Bar</option>
|
75
|
+
</select>
|
76
|
+
|
77
|
+
<a href="FIX">Select project</a>
|
78
|
+
|
79
|
+
<select name="phaseid"></select>
|
80
|
+
|
81
|
+
<textarea name='remark'></textarea>
|
82
|
+
|
83
|
+
<input name="time" value="">
|
84
|
+
|
85
|
+
<select name="workperiod">
|
86
|
+
<option value="workperiod.id='1'" selected>Normal</option>
|
87
|
+
<option value="workperiod.id='2'" >Overtime</option>
|
88
|
+
</select>
|
89
|
+
|
90
|
+
<select name="billpercent">
|
91
|
+
<option value="billpercent.id='1'" >Normal (100%)</option>
|
92
|
+
<option value="billpercent.id='2'" >Overtime (200%)</option>
|
93
|
+
</select>
|
94
|
+
|
95
|
+
<input type="submit" value="Save">
|
96
|
+
</form>
|
97
|
+
</body>
|
98
|
+
</html>
|
99
|
+
}
|
100
|
+
|
101
|
+
phase_html = %q{The phase <input type="hidden" name="phaseid" value="phase.id='1'">}
|
102
|
+
|
103
|
+
@server.register(:get, '/time_registration', [ 200, nil, time_registration_html ])
|
104
|
+
@server.register(:post, '/dispatch.php', [ 200, nil, phase_html ])
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_register_hours
|
108
|
+
achoo(:verbose => $DEBUG) do
|
109
|
+
expect '1. Register hours'
|
110
|
+
expect_main_prompt
|
111
|
+
puts '1'
|
112
|
+
|
113
|
+
expect /Date \(\[today\] \| \?\)>/
|
114
|
+
puts '2010-05-25'
|
115
|
+
|
116
|
+
expect 'Recently used projects'
|
117
|
+
expect '1. foo: Foo'
|
118
|
+
expect '2. bar: Bar'
|
119
|
+
puts '2'
|
120
|
+
|
121
|
+
expect 'Phases'
|
122
|
+
expect '1. The phase'
|
123
|
+
|
124
|
+
expect 'Remark>'
|
125
|
+
puts 'A nice remark'
|
126
|
+
|
127
|
+
expect 'Hours [7:30]>'
|
128
|
+
puts '2'
|
129
|
+
|
130
|
+
expect 'Do you want to change the defaults for worktime period and/or billing percentage? [N/y]>'
|
131
|
+
puts 'y'
|
132
|
+
|
133
|
+
expect 'Worktime periods'
|
134
|
+
expect '1. Normal'
|
135
|
+
expect '2. Overtime'
|
136
|
+
expect 'Period [1]>'
|
137
|
+
puts '2'
|
138
|
+
|
139
|
+
expect 'Billing options'
|
140
|
+
expect '1. Normal (100%)'
|
141
|
+
expect '2. Overtime (200%)'
|
142
|
+
expect 'Billing [1]>'
|
143
|
+
puts '2'
|
144
|
+
|
145
|
+
expect ' date: "2010-05-25"'
|
146
|
+
expect ' project: "bar: Bar"'
|
147
|
+
expect ' phase: "The phase"'
|
148
|
+
expect ' remark: "A nice remark"'
|
149
|
+
expect ' hours: "2"'
|
150
|
+
expect ' worktime: "Overtime"'
|
151
|
+
expect ' billing: "Overtime (200%)"'
|
152
|
+
|
153
|
+
expect 'Submit? [Y/n]>'
|
154
|
+
puts 'n'
|
155
|
+
|
156
|
+
expect 'Cancelled'
|
157
|
+
expect_main_prompt
|
158
|
+
puts 'q'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# From http://dynamicorange.com/2009/02/18/ruby-mock-web-server/
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'rack'
|
5
|
+
require 'thin'
|
6
|
+
|
7
|
+
class AchievoMock
|
8
|
+
|
9
|
+
def initialize(port=4000)
|
10
|
+
@expectations = []
|
11
|
+
@server = Thin::Server.new('127.0.0.1', port, self)
|
12
|
+
@server.silent = true
|
13
|
+
@thread = Thread.new { @server.start }
|
14
|
+
sleep 1
|
15
|
+
@logger = Logger.new(File.dirname(__FILE__) + '/../../tmp/test.log')
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
@server.stop!
|
20
|
+
Thread.kill(@thread)
|
21
|
+
end
|
22
|
+
|
23
|
+
def register(method, path, response, env={})
|
24
|
+
env.merge!({
|
25
|
+
'REQUEST_METHOD' => method.to_s.upcase,
|
26
|
+
'REQUEST_PATH' => path,
|
27
|
+
})
|
28
|
+
response[1] = { 'Content-Type' => 'text/html', 'Content-Length' => response[2].length.to_s }
|
29
|
+
response[2] = [response[2]]
|
30
|
+
@logger.debug "Registered #{[env, response]}"
|
31
|
+
@expectations << [env, response]
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear
|
35
|
+
@expectations = []
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(env)
|
39
|
+
@logger.debug "Got request: #{env}"
|
40
|
+
|
41
|
+
if @expectations.empty?
|
42
|
+
@logger.debug('Got an unexpected request')
|
43
|
+
return error_page('Not expecting any request')
|
44
|
+
end
|
45
|
+
|
46
|
+
response = @expectations.first[1]
|
47
|
+
if expectation_satisified?(env, @expectations.shift)
|
48
|
+
@logger.debug "Responding with: #{response}"
|
49
|
+
return response
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_page(msg)
|
54
|
+
[500,
|
55
|
+
{ 'Content-Type' => 'text/plain',
|
56
|
+
'Content-Length' => msg.length.to_s
|
57
|
+
},
|
58
|
+
[msg]
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def expectation_satisified?(env, expectation)
|
63
|
+
expectationEnv = expectation[0]
|
64
|
+
matched = false
|
65
|
+
expectationEnv.each do |envKey, value|
|
66
|
+
matched = true
|
67
|
+
if value != env[envKey]
|
68
|
+
matched = false
|
69
|
+
@logger.debug('Unmet expectation')
|
70
|
+
return error_page('Expectation not met')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
matched
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'expect'
|
2
|
+
require 'pty'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class AchooRunner
|
6
|
+
|
7
|
+
include Test::Unit::Assertions
|
8
|
+
|
9
|
+
attr_accessor :reader
|
10
|
+
attr_accessor :writer
|
11
|
+
attr_accessor :pid
|
12
|
+
|
13
|
+
def initialize(reader, writer, pid)
|
14
|
+
self.reader = reader
|
15
|
+
self.writer = writer
|
16
|
+
self.pid = pid
|
17
|
+
end
|
18
|
+
|
19
|
+
def puts(str); writer.puts str; end
|
20
|
+
|
21
|
+
def expect(pattern)
|
22
|
+
stat = reader.expect(pattern, 3)
|
23
|
+
raise "Didn't find '#{pattern}' before timeout" if stat.nil?
|
24
|
+
stat
|
25
|
+
end
|
26
|
+
|
27
|
+
def expect_main_prompt
|
28
|
+
expect('[1]>')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def achoo(opts, &block)
|
33
|
+
|
34
|
+
options = {
|
35
|
+
:verbose => false,
|
36
|
+
}.merge(opts)
|
37
|
+
|
38
|
+
rc_file = File.dirname(__FILE__) << '/dot_achoo'
|
39
|
+
File.chmod(0600, rc_file)
|
40
|
+
cmd = 'ruby -Ilib bin/achoo --log --rcfile ' << rc_file
|
41
|
+
|
42
|
+
PTY.spawn(cmd) do |r, w, pid|
|
43
|
+
w.sync = true
|
44
|
+
$expect_verbose = options[:verbose]
|
45
|
+
|
46
|
+
runner = AchooRunner.new(r, w, pid)
|
47
|
+
begin
|
48
|
+
runner.instance_eval(&block)
|
49
|
+
rescue Exception => e
|
50
|
+
runner.flunk e
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#require 'redgreen' # FIX Seems to be problems with ruby 1.9.2 due to minitest/unit
|
2
|
+
require 'shoulda'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'achievo_mock'
|
6
|
+
require 'achoo_runner'
|
7
|
+
|
8
|
+
module AcceptanceBase
|
9
|
+
|
10
|
+
@@main_html = %q{
|
11
|
+
<html>
|
12
|
+
<head></head>
|
13
|
+
<frameset>
|
14
|
+
<frame name="menu" src="/menu">
|
15
|
+
<frameset>
|
16
|
+
</html>
|
17
|
+
}
|
18
|
+
|
19
|
+
@@menu_html = %q{
|
20
|
+
<html>
|
21
|
+
<head></head>
|
22
|
+
<body>
|
23
|
+
<a class="menuItemLevel2"
|
24
|
+
onclick="window.open('time_registration')">Time Registration</a>
|
25
|
+
<a class="menuItemLevel2"
|
26
|
+
onclick="window.open('lock_months')">Lock months</a>
|
27
|
+
<a class="menuItemLevel2"
|
28
|
+
onclick="window.open('holiday_report')">Holiday report</a>
|
29
|
+
</body>
|
30
|
+
</html>
|
31
|
+
}
|
32
|
+
|
33
|
+
def setup
|
34
|
+
@server = AchievoMock.new()
|
35
|
+
@server.register(:get, '/', [ 200, nil, @@main_html ])
|
36
|
+
@server.register(:get, '/menu', [ 200, nil, @@menu_html ])
|
37
|
+
end
|
38
|
+
|
39
|
+
def teardown
|
40
|
+
@server.stop
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'achoo/achievo'
|
2
|
+
require 'test_helpers'
|
3
|
+
|
4
|
+
class TestTermMenu < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context 'Include' do
|
7
|
+
setup do
|
8
|
+
@a = Class.new do
|
9
|
+
include Achoo::Achievo::DateField('foo', 'bar')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'mixin foo accessor' do
|
14
|
+
assert @a.instance_methods.include?('foo')
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'mixin foo= accessor' do
|
18
|
+
assert @a.instance_methods.include?('foo=')
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'mixin foo_day_field accessor' do
|
22
|
+
assert @a.instance_methods.include?('foo_day_field')
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'mixin foo_month_field accessor' do
|
26
|
+
assert @a.instance_methods.include?('foo_month_field')
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'mixin foo_year_field accessor' do
|
30
|
+
assert @a.instance_methods.include?('foo_year_field')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'achoo/awake'
|
2
|
+
require 'achoo/system'
|
3
|
+
require 'stringio'
|
4
|
+
require 'test_helpers'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
class Achoo::Awake
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
log = [
|
11
|
+
[ '1990-03-01 07:00', :boot],
|
12
|
+
[ '1990-03-01 11:40', :suspend],
|
13
|
+
# Crash
|
14
|
+
[ '1990-03-01 13:00', :boot],
|
15
|
+
[ '1990-03-01 18:00', :halt],
|
16
|
+
#
|
17
|
+
[ '1990-03-02 07:00', :boot],
|
18
|
+
[ '1990-03-02 08:00', :suspend],
|
19
|
+
[ '1990-03-02 09:00', :awake],
|
20
|
+
[ '1990-03-02 10:00', :suspend],
|
21
|
+
[ '1990-03-03 11:00', :awake],
|
22
|
+
[ '1990-03-03 12:00', :halt],
|
23
|
+
#
|
24
|
+
[ '1990-03-04 07:00', :boot],
|
25
|
+
# Crash
|
26
|
+
[ '1990-03-05 07:00', :boot],
|
27
|
+
[ '1990-03-05 08:00', :suspend],
|
28
|
+
[ '1990-03-05 09:00', :awake],
|
29
|
+
# Crash
|
30
|
+
[ '1990-03-05 10:00', :boot],
|
31
|
+
].reverse
|
32
|
+
log.unshift(['1990-03-05 18:00', :now])
|
33
|
+
|
34
|
+
log.each {|entry| entry[0] = Time.parse(entry[0])}
|
35
|
+
log.collect! {|entry| Achoo::System::LogEntry.new(*entry)}
|
36
|
+
|
37
|
+
@sessions = sessions(log)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class TestAwake < Test::Unit::TestCase
|
44
|
+
|
45
|
+
def setup
|
46
|
+
@awake = Achoo::Awake.new
|
47
|
+
end
|
48
|
+
|
49
|
+
#def teardown
|
50
|
+
#end
|
51
|
+
|
52
|
+
def test_all
|
53
|
+
$stdout = StringIO.new
|
54
|
+
|
55
|
+
@awake.all
|
56
|
+
expected = %q{Powered on: (0+08:00) Mon 5. Mar 1990 10:00 - 18:00
|
57
|
+
Powered on: (?+??:??) Mon 5. Mar 1990 07:00 - ?
|
58
|
+
Awake: (?+??:??) Mon 5. Mar 1990 09:00 - ?
|
59
|
+
Awake: (0+01:00) Mon 5. Mar 1990 07:00 - 08:00
|
60
|
+
Powered on: (?+??:??) Sun 4. Mar 1990 07:00 - ?
|
61
|
+
Powered on: (1+05:00) Fri 2. Mar 1990 07:00 - Sat 3. Mar 1990 12:00
|
62
|
+
Awake: (0+01:00) Sat 3. Mar 1990 11:00 - 12:00
|
63
|
+
Awake: (0+01:00) Fri 2. Mar 1990 09:00 - 10:00
|
64
|
+
Awake: (0+01:00) Fri 2. Mar 1990 07:00 - 08:00
|
65
|
+
Powered on: (0+05:00) Thu 1. Mar 1990 13:00 - 18:00
|
66
|
+
Powered on: (0+04:40) Thu 1. Mar 1990 07:00 - 11:40
|
67
|
+
}
|
68
|
+
actual = $stdout.string
|
69
|
+
$stdout = STDOUT
|
70
|
+
assert_equal(expected, actual)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_at_1
|
74
|
+
$stdout = StringIO.new
|
75
|
+
|
76
|
+
@awake.at(Date.new(1990, 3, 2))
|
77
|
+
expected = %q{Powered on: (1+05:00) Fri 2. Mar 1990 07:00 - Sat 3. Mar 1990 12:00
|
78
|
+
Awake: (0+01:00) Fri 2. Mar 1990 09:00 - 10:00
|
79
|
+
Awake: (0+01:00) Fri 2. Mar 1990 07:00 - 08:00
|
80
|
+
}
|
81
|
+
actual = $stdout.string
|
82
|
+
$stdout = STDOUT
|
83
|
+
assert_equal(expected, actual)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_at_2
|
87
|
+
$stdout = StringIO.new
|
88
|
+
|
89
|
+
@awake.at(Date.new(1990, 3, 3))
|
90
|
+
expected = %q{Powered on: (1+05:00) Fri 2. Mar 1990 07:00 - Sat 3. Mar 1990 12:00
|
91
|
+
Awake: (0+01:00) Sat 3. Mar 1990 11:00 - 12:00
|
92
|
+
}
|
93
|
+
actual = $stdout.string
|
94
|
+
$stdout = STDOUT
|
95
|
+
assert_equal(expected, actual)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|