daigaku 0.0.2 → 0.1.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 (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