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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -0
- data/README.md +25 -3
- data/Rakefile +3 -0
- data/daigaku.gemspec +3 -2
- data/lib/daigaku/configuration.rb +7 -4
- data/lib/daigaku/congratulator.rb +13 -0
- data/lib/daigaku/course.rb +5 -0
- data/lib/daigaku/generator.rb +13 -6
- data/lib/daigaku/github_client.rb +30 -0
- data/lib/daigaku/reference_solution.rb +10 -2
- data/lib/daigaku/solution.rb +19 -8
- data/lib/daigaku/storeable.rb +32 -0
- data/lib/daigaku/terminal/courses.rb +103 -11
- data/lib/daigaku/terminal/output.rb +6 -0
- data/lib/daigaku/terminal/texts/congratulations.txt +12 -0
- data/lib/daigaku/terminal.rb +2 -1
- data/lib/daigaku/test_result.rb +5 -3
- data/lib/daigaku/version.rb +1 -1
- data/lib/daigaku/views/chapters_menu.rb +19 -50
- data/lib/daigaku/views/courses_menu.rb +14 -49
- data/lib/daigaku/views/main_menu.rb +6 -6
- data/lib/daigaku/views/menu.rb +89 -0
- data/lib/daigaku/views/task_view.rb +29 -11
- data/lib/daigaku/views/top_bar.rb +9 -17
- data/lib/daigaku/views/units_menu.rb +21 -52
- data/lib/daigaku/views.rb +4 -12
- data/lib/daigaku/window.rb +46 -3
- data/lib/daigaku.rb +1 -4
- data/spec/daigaku/configuration_spec.rb +11 -11
- data/spec/daigaku/congratulator_spec.rb +24 -0
- data/spec/daigaku/course_spec.rb +18 -0
- data/spec/daigaku/generator_spec.rb +4 -4
- data/spec/daigaku/github_client_spec.rb +53 -0
- data/spec/daigaku/reference_solution_spec.rb +20 -2
- data/spec/daigaku/solution_spec.rb +13 -6
- data/spec/daigaku/storeable_spec.rb +35 -0
- data/spec/daigaku/terminal/courses_spec.rb +215 -5
- data/spec/daigaku/terminal/output_spec.rb +31 -3
- data/spec/daigaku/terminal_spec.rb +12 -2
- data/spec/daigaku/test_result_spec.rb +12 -2
- data/spec/daigaku/views/chapters_menu_spec.rb +1 -3
- data/spec/daigaku/views/courses_menu_spec.rb +1 -3
- data/spec/daigaku/views/menu_spec.rb +19 -0
- data/spec/daigaku/views/task_view_spec.rb +1 -1
- data/spec/daigaku/views/units_menu_spec.rb +1 -3
- data/spec/daigaku/views_spec.rb +0 -2
- data/spec/daigaku_spec.rb +0 -6
- data/spec/support/macros/content_helpers.rb +1 -1
- data/spec/support/macros/mock_helpers.rb +6 -1
- data/spec/support/macros/path_helpers.rb +12 -6
- data/spec/support/macros/resource_helpers.rb +3 -1
- metadata +33 -8
- data/lib/daigaku/database.rb +0 -64
- 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
|
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
|
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(
|
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
|
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(
|
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(
|
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
|
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
|
-
|
88
|
-
|
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
|
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
|
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
|
data/spec/daigaku/course_spec.rb
CHANGED
@@ -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(
|
46
|
-
expect(
|
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(
|
77
|
-
expect(
|
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
|
-
|
21
|
-
|
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
|
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
|
-
|
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
|
58
|
+
it "sets the solution's state in the store to verified if passed" do
|
52
59
|
subject.verify!
|
53
|
-
mastered =
|
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
|
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 =
|
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 "
|
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 "::
|
8
|
-
it "loads a text from a file in the
|
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
|
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
|
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
|