spinna 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Spinna
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ source_dir: '/foo'
2
+ history_size: 10
3
+ number_of_picks: 5
@@ -0,0 +1,2 @@
1
+ This is not a valid configuration file
2
+ so it will blow up.
@@ -0,0 +1,3 @@
1
+ # This configuration does not have a source_dir set.
2
+ foo: 'meh'
3
+ bar: 'blah'
@@ -0,0 +1,4 @@
1
+ # This configuration does not set the history_size
2
+
3
+ source_dir: '/foo'
4
+ number_of_picks: 5
@@ -0,0 +1,4 @@
1
+ # This configuration does not set the number of picks.
2
+
3
+ source_dir: '/foo'
4
+ history_size: 10
@@ -0,0 +1,3 @@
1
+ album 1
2
+ album 2
3
+ album 3
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'open3'
3
+
4
+ describe 'spinna get' do
5
+ before do
6
+ create_fake_source_dir
7
+ create_fake_data_dir
8
+ @download_dir = create_tmp_download_dir
9
+ ENV['SPINNA_DATA_DIR'] = File.join(Dir.tmpdir, 'spinna')
10
+ @wd = Dir.getwd
11
+ Dir.chdir(@download_dir)
12
+ end
13
+
14
+ after do
15
+ ENV.delete('SPINNA_DATA_DIR')
16
+ Dir.chdir(@wd)
17
+ end
18
+
19
+ context 'when used without any options' do
20
+ before do
21
+ Open3.popen3("#{@wd}/bin/spinna get") do |stdin, stdout, stderr, wait_thr|
22
+ @stdout = stdout.read
23
+ @stderr = stderr.read
24
+ @exit_status = wait_thr.value
25
+ end
26
+ end
27
+
28
+ it 'gets the number of albums set in the config from source_dir' do
29
+ # It must not have output any errors.
30
+ @stderr.must_be_empty
31
+
32
+ # Gets the correct number of picks
33
+ picks = @stdout.split("\n")
34
+ picks.size.must_equal 2
35
+
36
+ # Exits with a successful exit code
37
+ @exit_status.success?.must_equal true
38
+
39
+ # It added the picks to the history log
40
+ history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
41
+ history.split("\n").size.must_equal 2
42
+ end
43
+ end
44
+
45
+ context 'when given a -n (--number_of_picks) option' do
46
+ before do
47
+ Open3.popen3("#{@wd}/bin/spinna get -n 3") do |stdin, stdout, stderr, wait_thr|
48
+ @stdout = stdout.read
49
+ @stderr = stderr.read
50
+ @exit_status = wait_thr.value
51
+ end
52
+ end
53
+
54
+ it 'gets that number of albums from source_dir' do
55
+ # It must not output any errors
56
+ @stderr.must_be_empty
57
+
58
+ # Gets the correct number of picks
59
+ # picks = @stdout.split("\n")
60
+ # picks.size.must_equal 3
61
+
62
+ # Exits with a successful exit code
63
+ @exit_status.success?.must_equal true
64
+
65
+ # It updates the history log
66
+ history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
67
+ history.split("\n").size.must_equal 3
68
+ end
69
+ end
70
+
71
+ context 'when given a -p (--pattern) option' do
72
+ before do
73
+ Open3.popen3("#{@wd}/bin/spinna get -p \"album 1\" -n 1") do |stdin, stdout, stderr, wait_thr|
74
+ @stdout = stdout.read
75
+ @stderr = stderr.read
76
+ @exit_status = wait_thr.value
77
+ end
78
+ end
79
+
80
+ it 'picks only albums that match the given pattern' do
81
+ # It must not output any errors
82
+ @stderr.must_be_empty
83
+
84
+ # Gets the correct number of picks
85
+ picks = @stdout.split("\n")
86
+ picks.size.must_equal 1
87
+
88
+ # The pick should match the given pattern
89
+ picks.first.must_equal "Copying album 1..."
90
+
91
+ # Exits with a successful exit code
92
+ @exit_status.success?.must_equal true
93
+
94
+ # It updates the history log
95
+ history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
96
+ history.split("\n").size.must_equal 1
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,41 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/spec'
3
+ require 'minitest/pride'
4
+ require 'minitest-spec-context'
5
+ require 'mocha/mini_test'
6
+ require 'minitest/reporters'
7
+ require 'tmpdir'
8
+ require 'fileutils'
9
+
10
+ Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(:color => true)
11
+
12
+ def create_fake_source_dir
13
+ path = File.join(Dir.tmpdir, 'spinna_source_dir')
14
+ FileUtils.rm_rf(path)
15
+ FileUtils.mkdir(path)
16
+ 5.times do |i|
17
+ FileUtils.mkdir(File.join(path, "album #{i+1}"))
18
+ end
19
+ end
20
+
21
+ def create_fake_data_dir
22
+ path = File.join(Dir.tmpdir, 'spinna')
23
+ FileUtils.rm_rf(path)
24
+ FileUtils.mkdir(path)
25
+ config = {
26
+ 'source_dir' => File.join(Dir.tmpdir, 'spinna_source_dir'),
27
+ 'history_size' => 4,
28
+ 'number_of_picks' => 2
29
+ }
30
+ config_path = File.join(path, 'config.yml')
31
+ File.open(config_path, 'w+') do |f|
32
+ f.write config.to_yaml
33
+ end
34
+ end
35
+
36
+ def create_tmp_download_dir
37
+ path = File.join(Dir.tmpdir, 'spinna_download_dir')
38
+ FileUtils.rm_rf(path)
39
+ FileUtils.mkdir(path)
40
+ path
41
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+ require 'spinna/client'
3
+
4
+ describe Spinna::Client do
5
+ describe '.new' do
6
+ let(:config) { stub() }
7
+ let(:history) { stub() }
8
+ let(:picker) { stub() }
9
+ let(:music_library) { stub() }
10
+
11
+ before do
12
+ Spinna::Config.expects(:new).returns(config)
13
+ Spinna::History.expects(:new).returns(history)
14
+ Spinna::MusicLibrary.expects(:new).returns(music_library)
15
+ end
16
+
17
+ subject { Spinna::Client.new }
18
+
19
+ it 'assigns a config object to an instance variable' do
20
+ subject.config.must_equal config
21
+ end
22
+
23
+ it 'assigns a history object to an instance variable' do
24
+ subject.history.must_equal history
25
+ end
26
+
27
+ it 'assigns a music_library object to an instance variable' do
28
+ subject.library.must_equal music_library
29
+ end
30
+ end
31
+
32
+ describe '#get' do
33
+ let(:default_number_of_picks) { 2 }
34
+ let(:picker) { stub }
35
+ let(:music_library) { stub }
36
+ let(:picks) { ['album 1', 'album 2'] }
37
+
38
+ before do
39
+ Spinna::Config.stubs(:new).returns(config)
40
+ Spinna::History.stubs(:new).returns(history)
41
+ Spinna::Picker.stubs(:new).returns(picker)
42
+ Spinna::MusicLibrary.stubs(:new).returns(music_library)
43
+ end
44
+
45
+ context 'when called without arguments' do
46
+ let(:config) do
47
+ stub(
48
+ :number_of_picks => default_number_of_picks,
49
+ :source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
50
+ )
51
+ end
52
+ let(:history) { stub }
53
+ let(:picker) do
54
+ picker = stub
55
+ picker.stubs(:pick).returns(picks)
56
+ picker
57
+ end
58
+
59
+ subject { Spinna::Client.new }
60
+
61
+ it 'requests the default number of picks from the picker' do
62
+ picker.expects(:pick).with(default_number_of_picks, nil)
63
+ subject.get
64
+ end
65
+
66
+ it 'returns the picks from the picker' do
67
+ subject.get.must_equal picks
68
+ end
69
+ end
70
+
71
+ context 'when given a number_of_picks option' do
72
+ let(:config) do
73
+ stub(
74
+ :number_of_picks => default_number_of_picks,
75
+ :source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
76
+ )
77
+ end
78
+ let(:history) { stub }
79
+ let(:picker) { stub(:pick => [picks.first]) }
80
+
81
+ subject { Spinna::Client.new }
82
+
83
+ it 'requests the given number of picks from the picker' do
84
+ picker.expects(:pick).with(1, nil).returns([picks.first])
85
+ subject.get(:number_of_picks => 1)
86
+ end
87
+
88
+ it 'returns the picks from the picker' do
89
+ subject.get(:number_of_picks => 1).must_equal [picks.first]
90
+ end
91
+ end
92
+
93
+ context 'when given a pattern' do
94
+ let(:config) do
95
+ stub(
96
+ :number_of_picks => default_number_of_picks,
97
+ :source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
98
+ )
99
+ end
100
+ let(:history) { stub }
101
+ let(:picker) { stub(:pick => [picks.first]) }
102
+
103
+ subject { Spinna::Client.new }
104
+
105
+ it 'requests the picks from the picker with the correct options' do
106
+ picker.expects(:pick).with(1, 'foo').returns([picks.first])
107
+ subject.get(:number_of_picks => 1, :pattern => 'foo')
108
+ end
109
+
110
+ it 'returns the picks from the picker' do
111
+ subject.get(:number_of_picks => 1, :pattern => 'foo').must_equal [picks.first]
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+ require 'spinna/config'
3
+
4
+ describe Spinna::Config do
5
+ describe 'DEFAULT_HISTORY_SIZE' do
6
+ it 'is set to 50' do
7
+ Spinna::Config::DEFAULT_HISTORY_SIZE.must_equal 50
8
+ end
9
+ end
10
+
11
+ describe 'DEFAULT_NUMBER_OF_PICKS' do
12
+ it 'is set to 10' do
13
+ Spinna::Config::DEFAULT_NUMBER_OF_PICKS.must_equal 10
14
+ end
15
+ end
16
+
17
+ describe '#new' do
18
+ let(:data_dir) { File.expand_path("../../fixtures/data_dir", __FILE__) }
19
+ let(:non_existing_data_dir) { File.join(Dir.home, '.nonexisting') }
20
+
21
+ context 'when the data_dir does not exist' do
22
+ let(:opts) { {:data_dir => non_existing_data_dir} }
23
+
24
+ subject {
25
+ Hash.new(:foo => 'bar')
26
+ }
27
+
28
+ it 'creates it and raises error because the configuration file is missing' do
29
+ Dir.expects(:mkdir).with(opts[:data_dir], 0700)
30
+ proc { Spinna::Config.new(opts) }.must_raise Spinna::ConfigFileNotFoundError
31
+ end
32
+ end
33
+
34
+ context 'when the configuration file does not exist' do
35
+ let(:opts) { {:data_dir => non_existing_data_dir} }
36
+
37
+ subject do
38
+ Spinna::Config.new(opts)
39
+ end
40
+
41
+ before do
42
+ Dir.stubs(:mkdir)
43
+ end
44
+
45
+ it 'throws an exception' do
46
+ opts = {:data_dir => non_existing_data_dir}
47
+ err = proc { subject }.must_raise Spinna::ConfigFileNotFoundError
48
+ err.message.must_match %r{Could not find the configuration file.}
49
+ end
50
+ end
51
+
52
+ context 'when the configuration file is not valid json' do
53
+ it 'throws an exception' do
54
+ opts = {
55
+ :data_dir => data_dir,
56
+ :config_file => 'config1.yml'
57
+ }
58
+ err = proc { Spinna::Config.new(opts) }.must_raise Spinna::InvalidConfigFileError
59
+ err.message.must_match %r{Could not parse the configuration file.}
60
+ end
61
+ end
62
+
63
+ context 'when the source_dir config parameter is missing' do
64
+ it 'throws an exception' do
65
+ opts = {
66
+ :data_dir => data_dir,
67
+ :config_file => 'config2.yml'
68
+ }
69
+ err = proc { Spinna::Config.new(opts) }.must_raise Spinna::InvalidConfigFileError
70
+ err.message.must_match %r{You must set a source_dir in your configuration file.}
71
+ end
72
+ end
73
+
74
+ context 'when the configuration is valid and all parameters were provided' do
75
+ it 'sets the source_dir' do
76
+ opts = {
77
+ :data_dir => data_dir,
78
+ :config_file => 'config.yml'
79
+ }
80
+ config = Spinna::Config.new(opts)
81
+ config.source_dir.must_equal '/foo'
82
+ end
83
+
84
+ it 'sets the history_size' do
85
+ opts = {
86
+ :data_dir => data_dir,
87
+ :config_file => 'config.yml'
88
+ }
89
+ config = Spinna::Config.new(opts)
90
+ config.history_size.must_equal 10
91
+ end
92
+
93
+ it 'sets the number_of_picks' do
94
+ opts = {
95
+ :data_dir => data_dir,
96
+ :config_file => 'config.yml'
97
+ }
98
+ config = Spinna::Config.new(opts)
99
+ config.number_of_picks.must_equal 5
100
+ end
101
+ end
102
+
103
+ context 'when the configuration is valid but the history_size was not provided' do
104
+ it 'uses the default value' do
105
+ opts = {
106
+ :data_dir => data_dir,
107
+ :config_file => 'config3.yml'
108
+ }
109
+ config = Spinna::Config.new(opts)
110
+ config.history_size.must_equal Spinna::Config::DEFAULT_HISTORY_SIZE
111
+ end
112
+ end
113
+
114
+ context 'when the configuration is valid but the number_of_picks was not provided' do
115
+ it 'uses the default value' do
116
+ opts = {
117
+ :data_dir => data_dir,
118
+ :config_file => 'config4.yml'
119
+ }
120
+ config = Spinna::Config.new(opts)
121
+ config.number_of_picks.must_equal Spinna::Config::DEFAULT_NUMBER_OF_PICKS
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+ require 'spinna/history'
3
+ require 'spinna/config'
4
+
5
+ describe Spinna::History do
6
+ let(:data_dir) { File.expand_path("../../fixtures/data_dir", __FILE__) }
7
+ let(:opts) { {:data_dir => data_dir} }
8
+ let(:config) { Spinna::Config.new(opts) }
9
+ let(:history_size) { 3 }
10
+
11
+ describe '#new' do
12
+ subject { Spinna::History.new(config) }
13
+
14
+ it 'saves the passed in config in an instance variable' do
15
+ subject.config.must_equal config
16
+ end
17
+
18
+ it 'reads the history log from the filesystem' do
19
+ subject.log.size.must_equal history_size
20
+ end
21
+ end
22
+
23
+ describe '#append' do
24
+ subject { Spinna::History.new(config) }
25
+
26
+ context 'when the album is not in the history' do
27
+ it 'appends the album at the end of the history log' do
28
+ size_before_append = subject.log.size
29
+ subject.append('album 11')
30
+ subject.log.size.must_equal size_before_append + 1
31
+ subject.log.last.must_equal 'album 11'
32
+ end
33
+ end
34
+
35
+ context 'when the album is already in the history' do
36
+ it 'does nothing' do
37
+ size_before_append = subject.log.size
38
+ subject.append('album 1')
39
+ subject.log.size.must_equal size_before_append
40
+ end
41
+ end
42
+
43
+ context 'when the history log is full' do
44
+ it 'removes the old albums from the log to make room for the new albums' do
45
+ subject.config.history_size = 3
46
+ subject.append('album 4')
47
+ subject.log.size.must_equal 3
48
+ subject.log.first.must_equal 'album 2'
49
+ subject.log.last.must_equal 'album 4'
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#include?' do
55
+ subject { Spinna::History.new(config) }
56
+
57
+ context 'when the album is in the log' do
58
+ it 'returns true' do
59
+ subject.include?('album 1').must_equal true
60
+ end
61
+ end
62
+
63
+ context 'when the album is not in the log' do
64
+ it 'returns false' do
65
+ subject.include?('album 99').must_equal false
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '#save' do
71
+ # This is used to fake writing the history.log file.
72
+ let(:fake_history_log) { StringIO.new('', 'w+') }
73
+
74
+ it 'saves the log to the filesystem' do
75
+ subject = Spinna::History.new(config)
76
+ # Use of mocking here so that we don’t actually write to the filesystem.
77
+ File.expects(:open).with(subject.history_path, 'w+').yields(fake_history_log)
78
+ subject.save
79
+ fake_history_log.string.must_equal "album 1\nalbum 2\nalbum 3\n"
80
+ end
81
+ end
82
+ end