daigaku 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/README.md +25 -3
  4. data/Rakefile +3 -0
  5. data/daigaku.gemspec +3 -2
  6. data/lib/daigaku/configuration.rb +7 -4
  7. data/lib/daigaku/congratulator.rb +13 -0
  8. data/lib/daigaku/course.rb +5 -0
  9. data/lib/daigaku/generator.rb +13 -6
  10. data/lib/daigaku/github_client.rb +30 -0
  11. data/lib/daigaku/reference_solution.rb +10 -2
  12. data/lib/daigaku/solution.rb +19 -8
  13. data/lib/daigaku/storeable.rb +32 -0
  14. data/lib/daigaku/terminal/courses.rb +103 -11
  15. data/lib/daigaku/terminal/output.rb +6 -0
  16. data/lib/daigaku/terminal/texts/congratulations.txt +12 -0
  17. data/lib/daigaku/terminal.rb +2 -1
  18. data/lib/daigaku/test_result.rb +5 -3
  19. data/lib/daigaku/version.rb +1 -1
  20. data/lib/daigaku/views/chapters_menu.rb +19 -50
  21. data/lib/daigaku/views/courses_menu.rb +14 -49
  22. data/lib/daigaku/views/main_menu.rb +6 -6
  23. data/lib/daigaku/views/menu.rb +89 -0
  24. data/lib/daigaku/views/task_view.rb +29 -11
  25. data/lib/daigaku/views/top_bar.rb +9 -17
  26. data/lib/daigaku/views/units_menu.rb +21 -52
  27. data/lib/daigaku/views.rb +4 -12
  28. data/lib/daigaku/window.rb +46 -3
  29. data/lib/daigaku.rb +1 -4
  30. data/spec/daigaku/configuration_spec.rb +11 -11
  31. data/spec/daigaku/congratulator_spec.rb +24 -0
  32. data/spec/daigaku/course_spec.rb +18 -0
  33. data/spec/daigaku/generator_spec.rb +4 -4
  34. data/spec/daigaku/github_client_spec.rb +53 -0
  35. data/spec/daigaku/reference_solution_spec.rb +20 -2
  36. data/spec/daigaku/solution_spec.rb +13 -6
  37. data/spec/daigaku/storeable_spec.rb +35 -0
  38. data/spec/daigaku/terminal/courses_spec.rb +215 -5
  39. data/spec/daigaku/terminal/output_spec.rb +31 -3
  40. data/spec/daigaku/terminal_spec.rb +12 -2
  41. data/spec/daigaku/test_result_spec.rb +12 -2
  42. data/spec/daigaku/views/chapters_menu_spec.rb +1 -3
  43. data/spec/daigaku/views/courses_menu_spec.rb +1 -3
  44. data/spec/daigaku/views/menu_spec.rb +19 -0
  45. data/spec/daigaku/views/task_view_spec.rb +1 -1
  46. data/spec/daigaku/views/units_menu_spec.rb +1 -3
  47. data/spec/daigaku/views_spec.rb +0 -2
  48. data/spec/daigaku_spec.rb +0 -6
  49. data/spec/support/macros/content_helpers.rb +1 -1
  50. data/spec/support/macros/mock_helpers.rb +6 -1
  51. data/spec/support/macros/path_helpers.rb +12 -6
  52. data/spec/support/macros/resource_helpers.rb +3 -1
  53. metadata +33 -8
  54. data/lib/daigaku/database.rb +0 -64
  55. data/spec/daigaku/database_spec.rb +0 -79
@@ -49,43 +49,43 @@ describe Daigaku::Configuration do
49
49
  end
50
50
 
51
51
  describe "#storage_path" do
52
- it "returns the appropriate path to the storge file" do
52
+ it "returns the appropriate path to the storage file" do
53
53
  expect(subject.storage_file).to eq local_storage_file
54
54
  end
55
55
  end
56
56
 
57
57
  describe "#save" do
58
- it "saves the configured courses path to the daigaku database" do
58
+ it "saves the configured courses path to the daigaku store" do
59
59
  subject.courses_path = local_courses_path
60
60
  subject.save
61
61
 
62
- expect(Daigaku::Database.courses_path).to eq local_courses_path
62
+ expect(QuickStore.store.courses_path).to eq local_courses_path
63
63
  end
64
64
 
65
- it "saves the configured solution_path to the daigaku database" do
65
+ it "saves the configured solution_path to the daigaku store" do
66
66
  path = File.join(test_basepath, 'test_solutions')
67
67
  FileUtils.makedirs(path)
68
68
  subject.solutions_path = path
69
69
  subject.save
70
70
 
71
- expect(Daigaku::Database.solutions_path).to eq path
71
+ expect(QuickStore.store.solutions_path).to eq path
72
72
  end
73
73
 
74
74
  it "does not save the storage file path" do
75
75
  subject.save
76
- expect(Daigaku::Database.storage_file).to be_nil
76
+ expect(QuickStore.store.storage_file).to be_nil
77
77
  end
78
78
  end
79
79
 
80
80
  describe "#import!" do
81
- context "with non-existent daigaku database entries:" do
81
+ context "with non-existent daigaku store entries:" do
82
82
  before do
83
83
  FileUtils.rm(local_storage_file) if File.exist?(local_storage_file)
84
84
  end
85
85
 
86
86
  it "uses the default configuration" do
87
- Daigaku::Database.courses_path = nil
88
- Daigaku::Database.solutions_path = nil
87
+ QuickStore.store.courses_path = nil
88
+ QuickStore.store.solutions_path = nil
89
89
  subject.instance_variable_set(:@courses_path, local_courses_path)
90
90
 
91
91
  loaded_config = subject.import!
@@ -96,12 +96,12 @@ describe Daigaku::Configuration do
96
96
  end
97
97
  end
98
98
 
99
- context "with existing daigaku database file:" do
99
+ context "with existing daigaku storage file:" do
100
100
  it "returns a Daigaku::Configuration" do
101
101
  expect(subject.import!).to be_a Daigaku::Configuration
102
102
  end
103
103
 
104
- it "loads the daigaku database entries into the configuration" do
104
+ it "loads the daigaku store entries into the configuration" do
105
105
  wanted_courses_path = "/courses/path"
106
106
  wanted_solutions_path = solutions_basepath
107
107
  temp_solutions_path = File.join(solutions_basepath, 'temp')
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Congratulator do
4
+
5
+ it "responds to #message" do
6
+ expect(Daigaku::Congratulator).to respond_to :message
7
+ end
8
+
9
+ describe "#message" do
10
+ it "returns a string" do
11
+ expect(Daigaku::Congratulator.message).to be_a String
12
+ end
13
+
14
+ it "returns a random congratulation method" do
15
+ messages = 1.upto(10).map { |i| Daigaku::Congratulator.message }
16
+ expect(messages.uniq.count).to be > 1
17
+ end
18
+
19
+ it "receives the congratulation texts from a Terminal text" do
20
+ expect(Daigaku::Terminal).to receive(:text).with(:congratulations) { '' }
21
+ Daigaku::Congratulator.message
22
+ end
23
+ end
24
+ end
@@ -72,4 +72,22 @@ describe Daigaku::Course do
72
72
  expect(subject.mastered?).to be false
73
73
  end
74
74
  end
75
+
76
+ describe "#key" do
77
+ it "returns the courses store key for the given key name" do
78
+ allow(subject).to receive(:title) { '1-Course title' }
79
+ key = "courses/course_title/some_key"
80
+ expect(subject.key('1-some Key')).to eq key
81
+ end
82
+ end
83
+
84
+ describe "#author" do
85
+ it "returns the author of Github courses form the store" do
86
+ author = 'author'
87
+ QuickStore.store.set(subject.key(:author), author)
88
+
89
+ course = Daigaku::Course.new(course_path)
90
+ expect(course.author).to eq author
91
+ end
92
+ end
75
93
  end
@@ -42,8 +42,8 @@ describe Daigaku::Generator do
42
42
 
43
43
  it "saves the current config info" do
44
44
  expect(File.exist?(local_storage_file)).to be_truthy
45
- expect(Daigaku::Database.courses_path).to eq local_courses_path
46
- expect(Daigaku::Database.solutions_path).to eq solutions_basepath
45
+ expect(QuickStore.store.courses_path).to eq local_courses_path
46
+ expect(QuickStore.store.solutions_path).to eq solutions_basepath
47
47
  end
48
48
  end
49
49
 
@@ -73,8 +73,8 @@ describe Daigaku::Generator do
73
73
 
74
74
  it "saves the current config info" do
75
75
  expect(File.exist?(local_storage_file)).to be_truthy
76
- expect(Daigaku::Database.courses_path).to eq local_courses_path
77
- expect(Daigaku::Database.solutions_path).to eq @solutions_path
76
+ expect(QuickStore.store.courses_path).to eq local_courses_path
77
+ expect(QuickStore.store.solutions_path).to eq @solutions_path
78
78
  end
79
79
  end
80
80
  end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::GithubClient do
4
+
5
+ describe "#master_zip_url" do
6
+ it "returns the url to the master zip file for the given github repo" do
7
+ url = "https://github.com/a/b/archive/master.zip"
8
+ expect(Daigaku::GithubClient.master_zip_url('a/b')).to eq url
9
+ end
10
+ end
11
+
12
+ describe "#updated_at" do
13
+ it "fetches the updated_at timestamp from the Github API" do
14
+ expected_timestamp = "2015-10-21T12:00:00Z"
15
+ response = { updated_at: expected_timestamp }.to_json
16
+ url = "https://api.github.com/repos/a/b"
17
+
18
+ stub_request(:get, url)
19
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
20
+ .to_return(status: 200, body: response, headers: {})
21
+
22
+ timestamp = Daigaku::GithubClient.updated_at('a/b')
23
+
24
+ expect(timestamp).to eq expected_timestamp
25
+ end
26
+ end
27
+
28
+ describe "#updated?" do
29
+ before do
30
+ @received_timestamp = "2015-10-21T12:00:00Z"
31
+ response = { updated_at: @received_timestamp }.to_json
32
+ url = "https://api.github.com/repos/a/b"
33
+
34
+ stub_request(:get, url)
35
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
36
+ .to_return(status: 200, body: response, headers: {})
37
+ end
38
+
39
+ it "returns true if content was pushed to the Github repo" do
40
+ QuickStore.store.set('courses/b/updated_at', "2015-10-21T11:59:59Z")
41
+ expect(Daigaku::GithubClient.updated?('a/b')).to be_truthy
42
+ end
43
+
44
+ it "returns false if no content was pushed to the Github repo" do
45
+ QuickStore.store.set('courses/b/updated_at', @received_timestamp)
46
+ expect(Daigaku::GithubClient.updated?('a/b')).to be_falsey
47
+ end
48
+
49
+ it "returns false if param is nil" do
50
+ expect(Daigaku::GithubClient.updated?(nil)).to be_falsey
51
+ end
52
+ end
53
+ end
@@ -4,6 +4,7 @@ describe Daigaku::ReferenceSolution do
4
4
 
5
5
  it { is_expected.to respond_to :code }
6
6
  it { is_expected.to respond_to :path }
7
+ it { is_expected.to respond_to :code_lines }
7
8
 
8
9
  let(:unit_path) do
9
10
  course_name = course_dir_names.first
@@ -17,7 +18,24 @@ describe Daigaku::ReferenceSolution do
17
18
  expect(subject.path).to eq path
18
19
  end
19
20
 
20
- it "has the prescribed code" do
21
- expect(subject.code).to eq solution_content
21
+ describe "#code" do
22
+ it "has the prescribed code" do
23
+ expect(subject.code).to eq solution_content
24
+ end
25
+
26
+ it "returns an empty string if the code is not available" do
27
+ subject.instance_variable_set(:@code, nil)
28
+ expect(subject.code).to eq ""
29
+ end
30
+ end
31
+
32
+
33
+ describe "#code_lines" do
34
+ it "returns the code split into lines" do
35
+ lines = ['muffin = "sweet"', 'hamburger = "mjummy"']
36
+ allow(subject).to receive(:code) { lines.join("\n") }
37
+
38
+ expect(subject.code_lines).to eq lines
39
+ end
22
40
  end
23
41
  end
@@ -26,13 +26,20 @@ describe Daigaku::Solution do
26
26
  expect(subject.code).to eq solution_content
27
27
  end
28
28
 
29
- it "loads the verified state from the database on creation" do
29
+ it "loads the verified state from the store on creation" do
30
30
  Daigaku::Solution.new(unit_path).verify!
31
31
  solution = Daigaku::Solution.new(unit_path)
32
32
 
33
33
  expect(solution).to be_verified
34
34
  end
35
35
 
36
+ describe "#store_key" do
37
+ it "returns the appropriate key string for the solution" do
38
+ key = "verified/course_a/chapter_a/unit_a"
39
+ expect(subject.store_key).to eq key
40
+ end
41
+ end
42
+
36
43
  context "Verification" do
37
44
  describe "#verify!" do
38
45
  it "returns a TestResult" do
@@ -40,7 +47,7 @@ describe Daigaku::Solution do
40
47
  end
41
48
 
42
49
  it "sets @verified true if Test passed" do
43
- Daigaku::Database.set(subject.path, false)
50
+ QuickStore.store.set(subject.store_key, false)
44
51
  solution = Daigaku::Solution.new(unit_path)
45
52
 
46
53
  expect(solution.instance_variable_get(:@verified)).to be_falsey
@@ -48,17 +55,17 @@ describe Daigaku::Solution do
48
55
  expect(solution.instance_variable_get(:@verified)).to be_truthy
49
56
  end
50
57
 
51
- it "sets the solution's state in the database to verified if passed" do
58
+ it "sets the solution's state in the store to verified if passed" do
52
59
  subject.verify!
53
- mastered = Daigaku::Database.get(subject.path)
60
+ mastered = QuickStore.store.get(subject.store_key)
54
61
 
55
62
  expect(mastered).to be_truthy
56
63
  end
57
64
 
58
- it "sets the solution's state in the database to unverified unless passed" do
65
+ it "sets the solution's state in the store to unverified unless passed" do
59
66
  subject.instance_variable_set(:@code, 'puts "I ❤ Daigaku!"')
60
67
  subject.verify!
61
- mastered = Daigaku::Database.get(subject.path)
68
+ mastered = QuickStore.store.get(subject.store_key)
62
69
 
63
70
  expect(mastered).to be_falsey
64
71
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Daigaku::Storeable do
4
+
5
+ it "responds to ::key" do
6
+ expect(Daigaku::Storeable).to respond_to :key
7
+ end
8
+
9
+ describe '::key' do
10
+ it "creates a store key from the given string" do
11
+ key = Daigaku::Storeable.key('1-_Raw content-Title')
12
+ expect(key).to eq 'raw_content_title'
13
+ end
14
+
15
+ it "creates a cleaned up store key from a given path string" do
16
+ key = Daigaku::Storeable.key('path/to/the/1-_Raw content string')
17
+ expect(key).to eq 'path/to/the/raw_content_string'
18
+ end
19
+
20
+ it "creates a prefixed key when a prefix option is given" do
21
+ key = Daigaku::Storeable.key('1-_Raw content-Title', prefix: 'courses')
22
+ expect(key).to eq 'courses/raw_content_title'
23
+ end
24
+
25
+ it "creates a suffixed key if a suffix option is given" do
26
+ key = Daigaku::Storeable.key('1-_Raw content-Title', suffix: '1-author')
27
+ expect(key).to eq 'raw_content_title/author'
28
+ end
29
+
30
+ it "creates a multi suffixed key if a suffixes option is given" do
31
+ key = Daigaku::Storeable.key('1-_Raw content-Title', suffixes: ['meta', '1-author'] )
32
+ expect(key).to eq 'raw_content_title/meta/author'
33
+ end
34
+ end
35
+ end
@@ -13,7 +13,6 @@ describe Daigaku::Terminal::Courses do
13
13
  end
14
14
 
15
15
  describe "#download" do
16
-
17
16
  before do
18
17
  Daigaku.config.courses_path = local_courses_path
19
18
 
@@ -28,6 +27,10 @@ describe Daigaku::Terminal::Courses do
28
27
  'User-Agent' => 'Ruby'
29
28
  })
30
29
  .to_return(status: 200, body: @file_content, headers: {})
30
+
31
+ stub_request(:get, "https://api.github.com/repos/daigaku-ruby/Get_started_with_Ruby")
32
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
33
+ .to_return(status: 200, body: "{}", headers: {})
31
34
  end
32
35
 
33
36
  after { cleanup_download(@zip_file_name) }
@@ -38,11 +41,7 @@ describe Daigaku::Terminal::Courses do
38
41
 
39
42
  it "creates a new courses folder in the daigaku courses directory" do
40
43
  target_path = File.join(Daigaku.config.courses_path, File.basename(course_dirs.first))
41
-
42
44
  dirs = Dir[File.join(Daigaku.config.courses_path, '**')]
43
- puts "target_path: #{target_path}"
44
- puts dirs.to_s
45
-
46
45
  expect(dirs.include?(target_path)).to be_truthy
47
46
  end
48
47
 
@@ -55,6 +54,217 @@ describe Daigaku::Terminal::Courses do
55
54
  expect(subject).to receive(:say_warning)
56
55
  subject.download('http://exmaple.com/something-else')
57
56
  end
57
+
58
+ describe "stores download data:" do
59
+ before do
60
+ @github_url = "https://github.com/user/course_a/archive/master.zip"
61
+
62
+ stub_request(:get, @github_url)
63
+ .with(headers: {
64
+ 'Accept' => '*/*',
65
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
66
+ 'User-Agent' => 'Ruby'
67
+ })
68
+ .to_return(status: 200, body: @file_content, headers: {})
69
+
70
+ stub_request(:get, "https://api.github.com/repos/course_a/repo")
71
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
72
+ .to_return(status: 200, body: "{}", headers: {})
73
+ end
74
+
75
+ it "stores the course's author for courses from Github" do
76
+ subject.download(@github_url)
77
+ store_key = 'courses/course_a/author'
78
+ expect(QuickStore.store.get(store_key)).to eq 'user'
79
+ end
80
+
81
+ it "stores the course's repo for courses from Github" do
82
+ subject.download(@github_url)
83
+ store_key = 'courses/course_a/github'
84
+ expect(QuickStore.store.get(store_key)).to eq 'user/course_a'
85
+ end
86
+
87
+ it "stores the downloading timestamp" do
88
+ time = Time.now
89
+ allow(Time).to receive(:now) { time }
90
+ subject.download(@url)
91
+ expect(QuickStore.store.get('courses/course_a/updated_at')).to eq time.to_s
92
+ end
93
+
94
+ it "stores the course's download url" do
95
+ subject.download(@url)
96
+ expect(QuickStore.store.get('courses/course_a/url')).to eq @url
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '#update' do
102
+ before do
103
+ Daigaku.config.courses_path = local_courses_path
104
+
105
+ @zip_file_name = "repo.zip"
106
+ @file_content = prepare_download(@zip_file_name)
107
+ @url = "https://example.com/#{@zip_file_name}"
108
+
109
+ stub_request(:get, @url)
110
+ .with(headers: {
111
+ 'Accept' => '*/*',
112
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
113
+ 'User-Agent' => 'Ruby'
114
+ })
115
+ .to_return(status: 200, body: @file_content, headers: {})
116
+
117
+ stub_request(:get, "https://api.github.com/repos/daigaku-ruby/Get_started_with_Ruby")
118
+ .with(headers: { 'Accept' => '*/*', 'User-Agent' => 'Ruby' })
119
+ .to_return(status: 200, body: "{}", headers: {})
120
+
121
+ allow(subject).to receive(:download) { true }
122
+ allow(Daigaku::GithubClient).to receive(:updated?) { |attr| true }
123
+ end
124
+
125
+ after { cleanup_download(@zip_file_name) }
126
+
127
+ it "updates a course that is not from Github on each call" do
128
+ url = 'https://example.com/repo.zip'
129
+ expect(subject).to receive(:download).with(url, 'updated').once
130
+ subject.update('Course_A')
131
+ end
132
+
133
+ it "updates a course from Github if there are new contents" do
134
+ url = "https://github.com/user/repo/archive/master.zip"
135
+
136
+ stub_request(:get, url)
137
+ .with(headers: {
138
+ 'Accept' => '*/*',
139
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
140
+ 'User-Agent' => 'Ruby'
141
+ })
142
+ .to_return(status: 200, body: @file_content, headers: {})
143
+
144
+ QuickStore.store.set('courses/course_a/url', url)
145
+
146
+ expect(subject).to receive(:download).with(url, 'updated').once
147
+ subject.update('Course_A')
148
+ end
149
+
150
+ it "does not update a course from Github if there are no new contents" do
151
+ allow(Daigaku::GithubClient).to receive(:updated?) { false }
152
+ url = "https://github.com/user/repo/archive/master.zip"
153
+
154
+ stub_request(:get, url)
155
+ .with(headers: {
156
+ 'Accept' => '*/*',
157
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
158
+ 'User-Agent' => 'Ruby'
159
+ })
160
+ .to_return(status: 200, body: @file_content, headers: {})
161
+
162
+ QuickStore.store.set('courses/course_a/url', url)
163
+ QuickStore.store.set('courses/course_a/github', 'user/repo')
164
+
165
+ expect(subject).not_to receive(:download)
166
+ subject.update('Course_A')
167
+ end
58
168
  end
59
169
 
170
+ describe '#delete' do
171
+ before do
172
+ Daigaku.config.courses_path = local_courses_path
173
+ @course_path = course_dirs.first
174
+ prepare_courses unless Dir.exist?(@course_path)
175
+ allow(subject).to receive(:get).and_return('yes')
176
+ end
177
+
178
+ describe "confirmation" do
179
+ it "is nessecary to delete all courses" do
180
+ allow(subject).to receive(:options) { { all: true } }
181
+ expect(subject).to receive(:get_confirm)
182
+ subject.delete
183
+ end
184
+
185
+ it "is nessecary to delete a certain course" do
186
+ expect(subject).to receive(:get_confirm)
187
+ subject.delete(course_dir_names.first)
188
+ end
189
+ end
190
+
191
+ context "when confirmed:" do
192
+ it "deletes the given course" do
193
+ expect(Dir.exist?(@course_path)).to be_truthy
194
+ subject.delete(course_dir_names.first)
195
+ expect(Dir.exist?(@course_path)).to be_falsey
196
+ end
197
+
198
+ it "deletes all courses with option --all" do
199
+ allow(subject).to receive(:options) { { all: true } }
200
+ expect(Dir.exist?(@course_path)).to be_truthy
201
+ subject.delete
202
+
203
+ course_dirs.each do |dir|
204
+ expect(Dir.exist?(dir)).to be_falsey
205
+ end
206
+ end
207
+ end
208
+
209
+ context "when not confirmed:" do
210
+ before { allow(subject).to receive(:get).and_return('no') }
211
+
212
+ it "does not delete the given course" do
213
+ expect(Dir.exist?(@course_path)).to be_truthy
214
+ subject.delete(course_dir_names.first)
215
+ expect(Dir.exist?(@course_path)).to be_truthy
216
+ end
217
+
218
+ it "does not delete all courses" do
219
+ allow(subject).to receive(:options) { { all: true } }
220
+ expect(Dir.exist?(@course_path)).to be_truthy
221
+ subject.delete
222
+
223
+ course_dirs.each do |dir|
224
+ expect(Dir.exist?(dir)).to be_truthy
225
+ end
226
+ end
227
+ end
228
+
229
+ describe "status information" do
230
+ it "is printed when a certain course was deleted" do
231
+ expect(subject).to receive(:say_info)
232
+ subject.delete(course_dir_names.first)
233
+ end
234
+
235
+ it "is printed when all courses were deleted" do
236
+ allow(subject).to receive(:options) { { all: true } }
237
+ expect(subject).to receive(:say_info)
238
+ subject.delete
239
+ end
240
+ end
241
+
242
+ describe "QuickStore data" do
243
+ it "is deleted for a certain course" do
244
+ key = Daigaku::Storeable.key(course_dir_names.first, prefix: 'courses')
245
+ QuickStore.store.set(key, 'some value')
246
+ subject.delete(course_dir_names.first)
247
+ expect(QuickStore.store.get(key)).to be_nil
248
+ end
249
+
250
+ it "is deleted for all courses when option --all is set" do
251
+ allow(subject).to receive(:options) { { all: true } }
252
+
253
+ keys = course_dir_names.map do |course_name|
254
+ Daigaku::Storeable.key(course_name, prefix: 'courses')
255
+ end
256
+
257
+ course_dir_names.each_with_index do |course_name, index|
258
+ QuickStore.store.set(keys[index], course_name)
259
+ end
260
+
261
+ subject.delete
262
+
263
+ course_dir_names.each_with_index do |course_name, index|
264
+ expect(QuickStore.store.get(keys[index])).to be_nil
265
+ end
266
+
267
+ end
268
+ end
269
+ end
60
270
  end
@@ -22,7 +22,8 @@ describe Daigaku::Terminal::Output do
22
22
  :get,
23
23
  :say_info,
24
24
  :say_warning,
25
- :get_command
25
+ :get_command,
26
+ :get_confirm
26
27
  ].each do |method|
27
28
  it "has the private method #{method}" do
28
29
  expect(subject.private_methods.include?(method)).to be_truthy
@@ -84,7 +85,6 @@ describe Daigaku::Terminal::Output do
84
85
  end
85
86
 
86
87
  describe "::get_command" do
87
-
88
88
  before do
89
89
  @correct_command = 'correct command'
90
90
  @description = 'description'
@@ -109,7 +109,7 @@ describe Daigaku::Terminal::Output do
109
109
  end
110
110
 
111
111
  context "with a wrong command typed in:" do
112
- it "writed a hint" do
112
+ it "writes a hint" do
113
113
  wrong_command = 'wrong command'
114
114
  error = "This was something else. Try \"#{@correct_command}\"."
115
115
  allow($stdin).to receive(:gets).and_return(wrong_command, @correct_command)
@@ -120,4 +120,32 @@ describe Daigaku::Terminal::Output do
120
120
  end
121
121
  end
122
122
 
123
+ describe "::get_confirm" do
124
+ before do
125
+ @description = 'description'
126
+ allow($stdin).to receive(:gets).and_return('yes')
127
+ end
128
+
129
+ it "prints a warning with the given description" do
130
+ expect(subject).to receive(:say_warning).once.with(@description)
131
+ subject.send(:get_confirm, @description)
132
+ end
133
+
134
+ it "gets a command from the $stdin" do
135
+ expect($stdin).to receive(:gets)
136
+ subject.send(:get_confirm, @description)
137
+ end
138
+
139
+ it "takes a block to run when confirmed" do
140
+ allow(subject).to receive(:mocked_method).and_return('mocked method')
141
+ expect(subject).to receive(:mocked_method)
142
+ subject.send(:get_confirm, @description) { subject.mocked_method }
143
+ end
144
+
145
+ it "does not run the given block if not confirmed" do
146
+ allow(subject).to receive(:get).and_return('no')
147
+ expect(subject).not_to receive(:mocked_method)
148
+ subject.send(:get_confirm, @description) { subject.mocked_method }
149
+ end
150
+ end
123
151
  end
@@ -4,11 +4,21 @@ describe Daigaku::Terminal do
4
4
 
5
5
  it { is_expected.to respond_to :text }
6
6
 
7
- describe "::load_text" do
8
- it "loads a text from a file in the cli/texts" do
7
+ describe "::text" do
8
+ it "loads a text from a file in the terminal/texts" do
9
9
  text = Daigaku::Terminal.text(:welcome)
10
10
  expect(text).to be_a String
11
11
  end
12
+
13
+ it "returns an empty string if the file does not exist" do
14
+ text = Daigaku::Terminal.text(:non_existent_text)
15
+ expect(text).to eq ''
16
+ end
17
+
18
+ it "returns an empty string if the file has no content" do
19
+ allow(File).to receive(:read) { '' }
20
+ expect(Daigaku::Terminal.text(:congratulations)).to eq ''
21
+ end
12
22
  end
13
23
 
14
24
  end
@@ -9,6 +9,7 @@ describe Daigaku::TestResult do
9
9
  it { is_expected.to respond_to :examples }
10
10
  it { is_expected.to respond_to :passed? }
11
11
  it { is_expected.to respond_to :summary }
12
+ it { is_expected.to respond_to :summary_lines }
12
13
 
13
14
  context "with passed input:" do
14
15
 
@@ -19,7 +20,7 @@ describe Daigaku::TestResult do
19
20
  end
20
21
 
21
22
  it "has a default summary" do
22
- expect(subject.summary).to eq test_passed_summary
23
+ expect(subject.summary).to include test_passed_summary
23
24
  end
24
25
  end
25
26
 
@@ -62,7 +63,7 @@ describe Daigaku::TestResult do
62
63
 
63
64
  expect(example.description).to eq description
64
65
  expect(example.status).to eq status
65
- expect(example.message).to eq message
66
+ expect(example.message).to include message
66
67
  end
67
68
  end
68
69
  end
@@ -78,4 +79,13 @@ describe Daigaku::TestResult do
78
79
  end
79
80
  end
80
81
 
82
+ describe "#summary_lines" do
83
+ it "returns the summary split into lines" do
84
+ lines = ['This', 'is', 'summary', 'for', 'a', 'test']
85
+ allow(subject).to receive(:summary) { lines.join("\n") }
86
+
87
+ expect(subject.summary_lines).to eq lines
88
+ end
89
+ end
90
+
81
91
  end