daigaku 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/README.md +62 -0
- data/Rakefile +2 -0
- data/bin/daigaku +12 -0
- data/daigaku.gemspec +37 -0
- data/lib/daigaku.rb +27 -0
- data/lib/daigaku/chapter.rb +23 -0
- data/lib/daigaku/configuration.rb +86 -0
- data/lib/daigaku/course.rb +23 -0
- data/lib/daigaku/database.rb +64 -0
- data/lib/daigaku/exceptions.rb +19 -0
- data/lib/daigaku/generator.rb +53 -0
- data/lib/daigaku/loadable.rb +23 -0
- data/lib/daigaku/loading/chapters.rb +9 -0
- data/lib/daigaku/loading/courses.rb +9 -0
- data/lib/daigaku/loading/units.rb +9 -0
- data/lib/daigaku/reference_solution.rb +10 -0
- data/lib/daigaku/solution.rb +42 -0
- data/lib/daigaku/task.rb +10 -0
- data/lib/daigaku/terminal.rb +11 -0
- data/lib/daigaku/terminal/cli.rb +59 -0
- data/lib/daigaku/terminal/courses.rb +114 -0
- data/lib/daigaku/terminal/output.rb +72 -0
- data/lib/daigaku/terminal/setup.rb +115 -0
- data/lib/daigaku/terminal/solutions.rb +46 -0
- data/lib/daigaku/terminal/texts/about.txt +19 -0
- data/lib/daigaku/terminal/texts/courses_empty.txt +3 -0
- data/lib/daigaku/terminal/texts/hint_course_download.txt +13 -0
- data/lib/daigaku/terminal/texts/welcome.txt +12 -0
- data/lib/daigaku/terminal/welcome.rb +98 -0
- data/lib/daigaku/test.rb +46 -0
- data/lib/daigaku/test_result.rb +69 -0
- data/lib/daigaku/unit.rb +28 -0
- data/lib/daigaku/version.rb +3 -0
- data/lib/daigaku/views.rb +59 -0
- data/lib/daigaku/views/chapters_menu.rb +91 -0
- data/lib/daigaku/views/courses_menu.rb +87 -0
- data/lib/daigaku/views/main_menu.rb +37 -0
- data/lib/daigaku/views/splash.rb +57 -0
- data/lib/daigaku/views/task_view.rb +206 -0
- data/lib/daigaku/views/top_bar.rb +48 -0
- data/lib/daigaku/views/units_menu.rb +92 -0
- data/lib/daigaku/window.rb +160 -0
- data/spec/daigaku/chapter_spec.rb +76 -0
- data/spec/daigaku/configuration_spec.rb +161 -0
- data/spec/daigaku/course_spec.rb +75 -0
- data/spec/daigaku/database_spec.rb +79 -0
- data/spec/daigaku/generator_spec.rb +82 -0
- data/spec/daigaku/loading/chapters_spec.rb +16 -0
- data/spec/daigaku/loading/courses_spec.rb +16 -0
- data/spec/daigaku/loading/units_spec.rb +21 -0
- data/spec/daigaku/reference_solution_spec.rb +23 -0
- data/spec/daigaku/solution_spec.rb +79 -0
- data/spec/daigaku/task_spec.rb +23 -0
- data/spec/daigaku/terminal/cli_spec.rb +51 -0
- data/spec/daigaku/terminal/courses_spec.rb +60 -0
- data/spec/daigaku/terminal/output_spec.rb +123 -0
- data/spec/daigaku/terminal/setup_spec.rb +10 -0
- data/spec/daigaku/terminal/solutions_spec.rb +8 -0
- data/spec/daigaku/terminal/welcome_spec.rb +12 -0
- data/spec/daigaku/terminal_spec.rb +14 -0
- data/spec/daigaku/test_example_spec.rb +54 -0
- data/spec/daigaku/test_result_spec.rb +81 -0
- data/spec/daigaku/test_spec.rb +48 -0
- data/spec/daigaku/unit_spec.rb +85 -0
- data/spec/daigaku/views/chapters_menu_spec.rb +8 -0
- data/spec/daigaku/views/courses_menu_spec.rb +8 -0
- data/spec/daigaku/views/task_view_spec.rb +7 -0
- data/spec/daigaku/views/units_menu_spec.rb +8 -0
- data/spec/daigaku/views_spec.rb +23 -0
- data/spec/daigaku_spec.rb +57 -0
- data/spec/path_helpers_spec.rb +60 -0
- data/spec/resource_helpers_spec.rb +33 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/macros/content_helpers.rb +129 -0
- data/spec/support/macros/mock_helpers.rb +20 -0
- data/spec/support/macros/path_helpers.rb +133 -0
- data/spec/support/macros/resource_helpers.rb +119 -0
- data/spec/support/macros/test_helpers.rb +6 -0
- metadata +361 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Daigaku::Views do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
class Test
|
7
|
+
include Daigaku::Views
|
8
|
+
end
|
9
|
+
|
10
|
+
Test.new
|
11
|
+
end
|
12
|
+
|
13
|
+
[
|
14
|
+
:default_window,
|
15
|
+
:top_bar,
|
16
|
+
:main_panel,
|
17
|
+
:sub_window_below_top_bar
|
18
|
+
].each do |method|
|
19
|
+
it "has a private method ::#{method}" do
|
20
|
+
expect(subject.private_methods.include?(method)).to be_truthy
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Daigaku module" do
|
4
|
+
|
5
|
+
describe "::config" do
|
6
|
+
|
7
|
+
subject { Daigaku.config }
|
8
|
+
|
9
|
+
[:config, :configure, :start].each do |method|
|
10
|
+
it "responds to ::#{method}" do
|
11
|
+
expect(Daigaku.singleton_methods).to include method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns Configuration of class Daigaku::Configuration" do
|
16
|
+
expect(subject).to be_an_instance_of Daigaku::Configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns a singleton setting" do
|
20
|
+
expect(subject).to be Daigaku.config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "::configure" do
|
25
|
+
|
26
|
+
let(:configure) do
|
27
|
+
proc do
|
28
|
+
Daigaku.configure do |config|
|
29
|
+
config.solutions_path = test_basepath
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "allows to configure the app" do
|
35
|
+
expect { configure.call }.not_to raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets configutation properties" do
|
39
|
+
configure.call
|
40
|
+
expect(Daigaku.config.solutions_path).to eq test_basepath
|
41
|
+
end
|
42
|
+
|
43
|
+
it "allows to change the config during runtime" do
|
44
|
+
Daigaku.configure do |config|
|
45
|
+
config.solutions_path = courses_basepath
|
46
|
+
end
|
47
|
+
|
48
|
+
expect(Daigaku.config.solutions_path).to eq courses_basepath
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "::database" do
|
53
|
+
it "returns a Diagaku::Database instance" do
|
54
|
+
expect(Daigaku.database).to be_a Daigaku::Database
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "PathHelpers" do
|
4
|
+
|
5
|
+
it "provides a temp base path" do
|
6
|
+
puts "\n* temp base path:"
|
7
|
+
puts temp_basepath
|
8
|
+
end
|
9
|
+
|
10
|
+
it "provides a test base path" do
|
11
|
+
puts "\n* test base path:"
|
12
|
+
puts test_basepath
|
13
|
+
end
|
14
|
+
|
15
|
+
it "provides a courses base path" do
|
16
|
+
puts "\n* courses base path:"
|
17
|
+
puts courses_basepath
|
18
|
+
end
|
19
|
+
|
20
|
+
it "provides the course directories" do
|
21
|
+
puts "\n* course dirs:"
|
22
|
+
puts course_dirs
|
23
|
+
end
|
24
|
+
|
25
|
+
it "provides each course's chapter directories" do
|
26
|
+
puts "\n* chapter dirs: "
|
27
|
+
|
28
|
+
course_dir_names.each do |course_name|
|
29
|
+
puts chapter_dirs(course_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "provides each chapter's unit directories" do
|
34
|
+
puts "\n* unit dirs:"
|
35
|
+
|
36
|
+
course_dir_names.each do |course_name|
|
37
|
+
puts unit_dirs(course_name)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "provides all unit directories as flattened array" do
|
42
|
+
puts "\n* all unit dirs:"
|
43
|
+
puts all_unit_dirs
|
44
|
+
end
|
45
|
+
|
46
|
+
it "provides all solution file paths" do
|
47
|
+
puts "\n* all solution file paths:"
|
48
|
+
puts all_solution_file_paths
|
49
|
+
end
|
50
|
+
|
51
|
+
it "provides all test file paths" do
|
52
|
+
puts "\n* all test file paths:"
|
53
|
+
puts all_test_file_paths
|
54
|
+
end
|
55
|
+
|
56
|
+
it "provides the local_storage_file path" do
|
57
|
+
puts "\n* local storage file path:"
|
58
|
+
puts local_storage_file
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ResourceHelpers" do
|
4
|
+
|
5
|
+
let(:course) { course_dir_names.first }
|
6
|
+
let(:chapter) { chapter_dir_names.first }
|
7
|
+
let(:unit) { unit_dir_names.first }
|
8
|
+
|
9
|
+
it "provides the available courses" do
|
10
|
+
puts "\n* available courses:"
|
11
|
+
puts available_courses.map &:inspect
|
12
|
+
end
|
13
|
+
|
14
|
+
it "provides a course's available chapters" do
|
15
|
+
puts "\n* available chapters:"
|
16
|
+
puts available_chapters(course).map &:inspect
|
17
|
+
end
|
18
|
+
|
19
|
+
it "provides a chapter's avaliable units" do
|
20
|
+
puts "\n* available units:"
|
21
|
+
puts available_units(course, chapter).map &:inspect
|
22
|
+
end
|
23
|
+
|
24
|
+
it "provides a unit's task file" do
|
25
|
+
puts "\n* task:"
|
26
|
+
puts available_task(course, chapter, unit).map &:inspect
|
27
|
+
end
|
28
|
+
|
29
|
+
it "provides a unit's reference solution file" do
|
30
|
+
puts "\n* reference solution:"
|
31
|
+
puts available_reference_solution(course, chapter, unit).map &:inspect
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'webmock/rspec'
|
3
|
+
|
4
|
+
def require_files_from(paths = [])
|
5
|
+
paths.each do |path|
|
6
|
+
Dir[File.join(File.expand_path("#{path}*.rb", __FILE__))].sort.each do |file|
|
7
|
+
require file
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.color = true
|
14
|
+
|
15
|
+
require File.expand_path('../../lib/daigaku', __FILE__)
|
16
|
+
require_files_from ["../support/**/"]
|
17
|
+
|
18
|
+
config.include TestHelpers
|
19
|
+
|
20
|
+
config.before(:each, type: :view) { mock_default_window }
|
21
|
+
|
22
|
+
config.before(:all) do
|
23
|
+
prepare_courses
|
24
|
+
use_test_storage_file
|
25
|
+
end
|
26
|
+
|
27
|
+
config.after(:all) { cleanup_temp_data }
|
28
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module ContentHelpers
|
2
|
+
|
3
|
+
TASK_FILE_CONTENT = [
|
4
|
+
"Heading\n======", "##Task",
|
5
|
+
"Solve this task!",
|
6
|
+
"##Hints",
|
7
|
+
"Just do it right..."
|
8
|
+
].join("\n\n")
|
9
|
+
|
10
|
+
SOLUTION_CONTENT = 'print "hello world".upcase'
|
11
|
+
|
12
|
+
TEST_CONTENT = [
|
13
|
+
"require 'rspec'\n",
|
14
|
+
"describe 'Your code' do",
|
15
|
+
" it 'prints out HELLO WORLD' do",
|
16
|
+
" expect { [['solution::code']] }.to output('HELLO WORLD').to_stdout",
|
17
|
+
" end\n",
|
18
|
+
" it 'uses the method #upcase to get capital letters' do",
|
19
|
+
" allow(self).to receive(:puts).and_return ''",
|
20
|
+
" allow(self).to receive(:print).and_return ''",
|
21
|
+
" expect_any_instance_of(String).to receive(:upcase).and_return('HELLO WORLD')\n",
|
22
|
+
" [['solution::code']]",
|
23
|
+
" end",
|
24
|
+
"end"
|
25
|
+
].join("\n")
|
26
|
+
|
27
|
+
TEST_FAILED_JSON =
|
28
|
+
%Q#
|
29
|
+
{ "examples":
|
30
|
+
[
|
31
|
+
{ "description": "description 1",
|
32
|
+
"full_description": "full description 1",
|
33
|
+
"status": "failed",
|
34
|
+
"file_path": "./spec.rb",
|
35
|
+
"line_number": 4,
|
36
|
+
"run_time": 0.001,
|
37
|
+
"exception": {
|
38
|
+
"class": "RSpec::Expectations::ExpectationNotMetError",
|
39
|
+
"message": "message 1",
|
40
|
+
"backtrace": ["backtrace 1_a", "backtrace 1_b"]
|
41
|
+
}
|
42
|
+
},
|
43
|
+
{ "description": "description 2",
|
44
|
+
"full_description": "full description 2",
|
45
|
+
"status": "passed",
|
46
|
+
"file_path": "./spec.rb",
|
47
|
+
"line_number": 8,
|
48
|
+
"run_time": 0.002
|
49
|
+
}
|
50
|
+
],
|
51
|
+
"summary": {
|
52
|
+
"duration": 0.003,
|
53
|
+
"example_count": 2,
|
54
|
+
"failure_count": 1,
|
55
|
+
"pending_count": 0
|
56
|
+
},
|
57
|
+
"summary_line": "2 example, 1 failure"
|
58
|
+
}
|
59
|
+
#
|
60
|
+
|
61
|
+
TEST_PASSED_JSON =
|
62
|
+
%Q#
|
63
|
+
{ "examples":
|
64
|
+
[
|
65
|
+
{ "description":"description 1",
|
66
|
+
"full_description":"full description 1",
|
67
|
+
"status":"passed",
|
68
|
+
"file_path":"spec.rb",
|
69
|
+
"line_number":4,
|
70
|
+
"run_time":0.001
|
71
|
+
},
|
72
|
+
{ "description":"description 2",
|
73
|
+
"full_description":"full description 2",
|
74
|
+
"status":"passed",
|
75
|
+
"file_path":"spec.rb",
|
76
|
+
"line_number":8,
|
77
|
+
"run_time":0.002
|
78
|
+
}
|
79
|
+
],
|
80
|
+
"summary":{
|
81
|
+
"duration":0.003,
|
82
|
+
"example_count":2,
|
83
|
+
"failure_count":0,
|
84
|
+
"pending_count":0
|
85
|
+
},
|
86
|
+
"summary_line":"2 example, 0 failures"
|
87
|
+
}
|
88
|
+
#
|
89
|
+
|
90
|
+
TEST_PASSED_MESSAGE = "Your code passed all tests. Congratulations!"
|
91
|
+
EXAMPLE_PASSED_MESSAGE = "Your code passed this requirement."
|
92
|
+
|
93
|
+
def task_file_content
|
94
|
+
TASK_FILE_CONTENT
|
95
|
+
end
|
96
|
+
|
97
|
+
def solution_content
|
98
|
+
SOLUTION_CONTENT
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_content
|
102
|
+
TEST_CONTENT
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_failed_json
|
106
|
+
TEST_FAILED_JSON
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_passed_json
|
110
|
+
TEST_PASSED_JSON
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_passed_json_parsed
|
114
|
+
JSON.parse(test_passed_json, symbolize_names: true)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_failed_json_parsed
|
118
|
+
JSON.parse(test_failed_json, symbolize_names: true)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_passed_summary
|
122
|
+
TEST_PASSED_MESSAGE
|
123
|
+
end
|
124
|
+
|
125
|
+
def example_passed_message
|
126
|
+
EXAMPLE_PASSED_MESSAGE
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MockHelpers
|
2
|
+
|
3
|
+
def mock_default_window
|
4
|
+
allow_any_instance_of(described_class).to receive(:default_window) { true }
|
5
|
+
end
|
6
|
+
|
7
|
+
def use_test_storage_file
|
8
|
+
Daigaku::Configuration.send(:new)
|
9
|
+
Daigaku.config.instance_variable_set(:@storage_file, local_storage_file)
|
10
|
+
Daigaku::Database.send(:new)
|
11
|
+
end
|
12
|
+
|
13
|
+
def suppress_print_out
|
14
|
+
allow(described_class).to receive(:say_warning) {}
|
15
|
+
allow(described_class).to receive(:say_info) {}
|
16
|
+
allow(described_class).to receive(:say) {}
|
17
|
+
allow($stdout).to receive(:puts) {}
|
18
|
+
allow($stdout).to receive(:print) {}
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module PathHelpers
|
2
|
+
LOCAL_DIR = '.daigaku'
|
3
|
+
CONFIGURATION_FILE = 'daigaku.settings'
|
4
|
+
COURSES = 'courses'
|
5
|
+
SOLUTIONS = 'solutions'
|
6
|
+
TEMP_PATH = File.expand_path("../../../../tmp/", __FILE__)
|
7
|
+
COURSE_DIR_NAMES = ['Course_A', 'Course_B']
|
8
|
+
CHAPTER_DIR_NAMES = ['Chapter-1', 'Chapter-2']
|
9
|
+
UNIT_DIR_NAMES = ['unit-1', 'unit-2']
|
10
|
+
TASK_NAME = 'task.md'
|
11
|
+
REFERENCE_SOLUTION_NAME = 'solution.rb'
|
12
|
+
TEST_NAME = 'solution_spec.rb'
|
13
|
+
STORAGE_FILE = 'daigaku.db.yml'
|
14
|
+
|
15
|
+
def temp_basepath
|
16
|
+
TEMP_PATH
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_basepath
|
20
|
+
File.join(TEMP_PATH, 'test')
|
21
|
+
end
|
22
|
+
|
23
|
+
def course_dir_names
|
24
|
+
COURSE_DIR_NAMES
|
25
|
+
end
|
26
|
+
|
27
|
+
def chapter_dir_names
|
28
|
+
CHAPTER_DIR_NAMES
|
29
|
+
end
|
30
|
+
|
31
|
+
def unit_dir_names
|
32
|
+
UNIT_DIR_NAMES
|
33
|
+
end
|
34
|
+
|
35
|
+
def task_name
|
36
|
+
TASK_NAME
|
37
|
+
end
|
38
|
+
|
39
|
+
def reference_solution_name
|
40
|
+
REFERENCE_SOLUTION_NAME
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_name
|
44
|
+
TEST_NAME
|
45
|
+
end
|
46
|
+
|
47
|
+
def courses_basepath
|
48
|
+
File.join(test_basepath, COURSES)
|
49
|
+
end
|
50
|
+
|
51
|
+
def solutions_basepath
|
52
|
+
File.join(test_basepath, SOLUTIONS)
|
53
|
+
end
|
54
|
+
|
55
|
+
def course_dirs
|
56
|
+
course_dir_names.map do |dir|
|
57
|
+
File.join(courses_basepath, dir)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def chapter_dirs(course_name)
|
62
|
+
chapter_dir_names.map do |chapter|
|
63
|
+
File.join(courses_basepath, course_name, chapter)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def unit_dirs(course_name)
|
68
|
+
chapter_dir_names.map do |chapter|
|
69
|
+
unit_dir_names.map do |unit|
|
70
|
+
File.join(courses_basepath, course_name, chapter, unit)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def all_unit_dirs
|
76
|
+
dirs = course_dirs.map do |course_dir|
|
77
|
+
chapter_dir_names.map do |chapter_name|
|
78
|
+
unit_dir_names.map do |unit_name|
|
79
|
+
File.join(course_dir, chapter_name, unit_name)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
dirs.flatten
|
85
|
+
end
|
86
|
+
|
87
|
+
def all_solution_file_paths
|
88
|
+
all_unit_dirs.map do |unit_dir|
|
89
|
+
underscored_unit_dir = File.basename(unit_dir).gsub(/(\_+|\-+|\.+)/, '_')
|
90
|
+
file_name = underscored_unit_dir + Daigaku::Generator::SOLUTION_SUFFIX
|
91
|
+
unit_path = File.join(solutions_basepath, unit_dir.split('/')[-3..-1])
|
92
|
+
|
93
|
+
File.join(File.dirname(unit_path), file_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def all_test_file_paths
|
98
|
+
all_unit_dirs.map do |unit_dir|
|
99
|
+
File.join(unit_dir, test_name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def course_titles
|
104
|
+
gsub_underscores(course_dir_names)
|
105
|
+
end
|
106
|
+
|
107
|
+
def chapter_titles
|
108
|
+
gsub_underscores(chapter_dir_names)
|
109
|
+
end
|
110
|
+
|
111
|
+
def unit_titles
|
112
|
+
gsub_underscores(unit_dir_names)
|
113
|
+
end
|
114
|
+
|
115
|
+
def gsub_underscores(names)
|
116
|
+
names.map { |unit| unit.gsub(/\_+/, ' ') }
|
117
|
+
end
|
118
|
+
|
119
|
+
def local_courses_path
|
120
|
+
local_path = File.join(test_basepath, LOCAL_DIR, COURSES)
|
121
|
+
File.expand_path(local_path, __FILE__)
|
122
|
+
end
|
123
|
+
|
124
|
+
def local_configuration_file
|
125
|
+
local_path = File.join(test_basepath, LOCAL_DIR, CONFIGURATION_FILE)
|
126
|
+
File.expand_path(local_path, __FILE__)
|
127
|
+
end
|
128
|
+
|
129
|
+
def local_storage_file
|
130
|
+
local_path = File.join(test_basepath, LOCAL_DIR, STORAGE_FILE)
|
131
|
+
File.expand_path(local_path, __FILE__)
|
132
|
+
end
|
133
|
+
end
|