scaffolder-tools 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.
@@ -0,0 +1,41 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','spec_helper'))
2
+
3
+ describe Scaffolder::Tool::Sequence do
4
+
5
+ it "should inherit from Scaffolder::Tool" do
6
+ described_class.superclass.should == Scaffolder::Tool
7
+ end
8
+
9
+ it "should return the description of the tool" do
10
+ desc = "Generate the fasta output for the scaffold"
11
+ described_class.description.should == desc
12
+ end
13
+
14
+ describe "execution when correctly instantiated" do
15
+
16
+ before(:each) do
17
+ entries = [{:name => 'seq1', :nucleotides => 'ATGC'}]
18
+
19
+ @scaffold_file = File.new("scaffold",'w').path
20
+ @sequence_file = File.new("sequence",'w').path
21
+
22
+ write_scaffold_file(entries,@scaffold_file)
23
+ write_sequence_file(entries,@sequence_file)
24
+ settings = mock_command_line_settings(@scaffold_file,@sequence_file,{
25
+ :definition => nil,:no => nil})
26
+
27
+ tool = described_class.new(settings)
28
+ @output = StringIO.new(tool.execute)
29
+ end
30
+
31
+ after(:each) do
32
+ File.delete @scaffold_file, @sequence_file
33
+ end
34
+
35
+ it "should return the expected sequence" do
36
+ Bio::FlatFile.auto(@output).first.seq.should == 'ATGC'
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,167 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'..','..','spec_helper'))
2
+
3
+ describe Scaffolder::Tool::Validate do
4
+
5
+ it "should inherit from Scaffolder::Tool" do
6
+ described_class.superclass.should == Scaffolder::Tool
7
+ end
8
+
9
+ it "should return the description of the tool" do
10
+ desc = "Validate scaffold for overlapping inserts"
11
+ described_class.description.should == desc
12
+ end
13
+
14
+ describe "comparing inserts for overlaps" do
15
+
16
+ before(:all) do
17
+ @insert = stub(:position => 5..10)
18
+ end
19
+
20
+ it "should be false when inserts don't overlap" do
21
+ no_overlap = stub(:position => 11..12)
22
+ described_class.inserts_overlap?(@insert,no_overlap).should be_false
23
+ described_class.inserts_overlap?(no_overlap,@insert).should be_false
24
+ end
25
+
26
+ it "should be true when inserts do overlap" do
27
+ overlap = stub(:position => 10..11)
28
+ described_class.inserts_overlap?(@insert,overlap).should be_true
29
+ described_class.inserts_overlap?(overlap,@insert).should be_true
30
+ end
31
+
32
+ end
33
+
34
+ describe "testing a sequence for overlapping inserts" do
35
+
36
+ before(:all) do
37
+ # Use integers for mocks because they can be easily sorted
38
+ @a = 1; @b = 2
39
+ @sequence = stub(:inserts => [@a,@b])
40
+ end
41
+
42
+ it "should return an empty array when sequence has no errors" do
43
+ described_class.stubs(:inserts_overlap?).with(@a,@b).returns(false)
44
+ described_class.stubs(:inserts_overlap?).with(@b,@a).returns(false)
45
+ described_class.sequence_errors(@sequence).empty?.should be_true
46
+ end
47
+
48
+ it "should return inserts when sequence inserts overlap" do
49
+ described_class.stubs(:inserts_overlap?).with(@a,@b).returns(true)
50
+ described_class.stubs(:inserts_overlap?).with(@b,@a).returns(true)
51
+ described_class.sequence_errors(@sequence).should == [[@a,@b]].sort
52
+ end
53
+
54
+ end
55
+
56
+ describe "validating each entry in the scaffold" do
57
+
58
+ before(:each) do
59
+ @valid = stub(:entry_type => :sequence)
60
+ @invalid = @valid.clone
61
+ described_class.stubs(:sequence_errors).with(@valid).returns([])
62
+ described_class.stubs(:sequence_errors).with(@invalid).returns([nil])
63
+ end
64
+
65
+ subject do
66
+ described_class.new(mock_command_line_settings)
67
+ end
68
+
69
+ it "should return an empty array when scaffold is valid" do
70
+ subject.expects(:scaffold).returns([@valid,@valid])
71
+ subject.errors.should be_empty
72
+ end
73
+
74
+ it "should return invalid entries when scaffold is invalid" do
75
+ subject.expects(:scaffold).returns([@invalid,@valid])
76
+ subject.errors.should == [@invalid]
77
+ end
78
+
79
+ it "should ignore entries which are not sequences" do
80
+ @non_sequence = stub(:entry_type => :other)
81
+ subject.expects(:scaffold).returns([@invalid,@valid,@non_sequence])
82
+ subject.errors.should == [@invalid]
83
+ end
84
+
85
+ end
86
+
87
+ describe "scaffold validation with no overlapping inserts" do
88
+
89
+ subject do
90
+ validate = described_class.new(mock_command_line_settings)
91
+ validate.stubs(:errors).returns([])
92
+ validate
93
+ end
94
+
95
+ it "should not raise any errors" do
96
+ lambda{ subject.execute }.should_not raise_error
97
+ end
98
+
99
+ it "should not return anything" do
100
+ subject.execute.should == nil
101
+ end
102
+
103
+ end
104
+
105
+ describe "returning errors using the errors method" do
106
+
107
+ subject do
108
+ validate = described_class.new(mock_command_line_settings)
109
+
110
+ sequence = stub(:source => :seq1)
111
+ validate.stubs(:errors).returns([sequence])
112
+ described_class.stubs(:sequence_errors).with(sequence).returns(
113
+ [[stub(:open => 1,:close => 2, :source => 'some_insert')]])
114
+
115
+ validate
116
+ end
117
+
118
+ it "should not raise an error" do
119
+ lambda{ subject.execute }.should_not raise_error
120
+ end
121
+
122
+ it "should return a string" do
123
+ subject.execute.should be_instance_of(String)
124
+ end
125
+
126
+ it "should be an array when YAML is parsed" do
127
+ lambda{ YAML.load(subject.execute) }.should_not raise_error
128
+ YAML.load(subject.execute).should be_instance_of(Array)
129
+ end
130
+
131
+ end
132
+
133
+ describe "the attributes of the error data" do
134
+
135
+ subject do
136
+ validate = described_class.new(mock_command_line_settings)
137
+ @err = {:open => 1,:close => 2,:source => 'some_insert'}
138
+
139
+ sequence = stub(:source => 'seq1')
140
+ validate.stubs(:errors).returns([sequence])
141
+ described_class.stubs(:sequence_errors).with(sequence).returns([[stub(@err)]])
142
+
143
+ YAML.load(validate.execute).first['sequence-insert-overlap']
144
+ end
145
+
146
+ it "should name each overlap entry 'sequence-insert-overlap'" do
147
+ subject.should_not be_nil
148
+ end
149
+
150
+ it "should provide the name of overlap containing sequence" do
151
+ subject['source'].should == 'seq1'
152
+ end
153
+
154
+ it "should provide an array of the overlapping inserts" do
155
+ subject['inserts'].should be_instance_of(Array)
156
+ end
157
+
158
+ it "should provide the coordinates of the overlapping inserts" do
159
+ error = subject['inserts'].first
160
+ error['open'].should == @err[:open]
161
+ error['close'].should == @err[:close]
162
+ error['source'].should == @err[:source]
163
+ end
164
+
165
+ end
166
+
167
+ end
@@ -0,0 +1,49 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe Scaffolder::ToolIndex do
4
+
5
+ before(:each) do
6
+ @help_tool = Scaffolder::Tool::Help
7
+
8
+ @tool_class = Class.new(Scaffolder::Tool)
9
+ @tool_name = 'type'
10
+ Scaffolder::Tool.const_set(@tool_name.capitalize,@tool_class)
11
+
12
+ @args = OpenStruct.new({ :rest => %W|#{@tool_name} arg1 arg2| })
13
+ end
14
+
15
+ after(:each) do
16
+ Scaffolder::Tool.send(:remove_const,'Type')
17
+ end
18
+
19
+ subject do
20
+ object = Object.new
21
+ object.extend described_class
22
+ object
23
+ end
24
+
25
+ describe "tool_exists? method" do
26
+
27
+ it "should return false when no such tool exists" do
28
+ subject.tool_exists?('unknown-tool').should be_false
29
+ end
30
+
31
+ it "should return true when the tool exists" do
32
+ subject.tool_exists?(@tool_name).should be_true
33
+ end
34
+
35
+ end
36
+
37
+ describe "get_tool method" do
38
+
39
+ it "should return nil when no such tool exists" do
40
+ subject.get_tool('unknown-tool').should be_nil
41
+ end
42
+
43
+ it "should return the tool class when the tool exists" do
44
+ subject.get_tool(@tool_name).should == @tool_class
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,147 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe Scaffolder::Tool do
4
+
5
+ describe "initialisation with attributes" do
6
+
7
+ before(:each) do
8
+ @settings = mock_command_line_settings
9
+ end
10
+
11
+ subject do
12
+ Scaffolder::Tool.new(@settings)
13
+ end
14
+
15
+ its(:scaffold_file){ should == @settings.scaffold_file }
16
+ its(:sequence_file){ should == @settings.sequence_file }
17
+ its(:settings){ should == @settings }
18
+ end
19
+
20
+ describe "the run method" do
21
+
22
+ before(:all) do
23
+ @settings = mock_command_line_settings
24
+ end
25
+
26
+ before(:each) do
27
+ @message = "output\n"
28
+ @out = StringIO.new
29
+ @err = StringIO.new
30
+ end
31
+
32
+ subject do
33
+ Scaffolder::Tool.new(@settings)
34
+ end
35
+
36
+ it "should print to standard out when there are no errors" do
37
+ subject.expects(:execute).returns(@message)
38
+ lambda{ subject.run(@out,@err) }.should raise_error
39
+ @err.string.should == ""
40
+ @out.string.should == @message
41
+ end
42
+
43
+ it "should print nothing to standard out when there no error and no output" do
44
+ subject.expects(:execute).returns(nil)
45
+ lambda{ subject.run(@out,@err) }.should raise_error
46
+ @err.string.should == ""
47
+ @out.string.should == ""
48
+ end
49
+
50
+ it "should give a zero exit code when there are no errors" do
51
+ subject.expects(:execute).returns(@message)
52
+ lambda{ subject.run(@out,@err) }.should exit_with_code(0)
53
+ end
54
+
55
+ it "should print to standard error when there are errors" do
56
+ subject.expects(:execute).raises(Exception, @message)
57
+ lambda{ subject.run(@out,@err) }.should raise_error
58
+ @out.string.should == ""
59
+ @err.string.should == "Error. #{@message}"
60
+ end
61
+
62
+ it "should give a non-zero exit code when there are errors" do
63
+ subject.expects(:execute).raises(Exception, @message)
64
+ lambda{ subject.run(@out,@err) }.should exit_with_code(1)
65
+ end
66
+
67
+ end
68
+
69
+ describe "error checking with the scaffold method" do
70
+
71
+ before(:each) do
72
+ FakeFS.activate!
73
+
74
+ @scaffold_file = File.new('scaffold','w').path
75
+ File.open(@scaffold_file,'w'){|out| out.write "some_content" }
76
+
77
+ @sequence_file = File.new('sequence','w').path
78
+ File.open(@sequence_file,'w'){|out| out.write "some_content" }
79
+
80
+ @empty_file = File.new('empty_file','w').path
81
+ File.open(@empty_file,'w'){|out| out.write "" }
82
+
83
+ @missing_file = "file"
84
+ end
85
+
86
+ after(:each) do
87
+ FakeFS.deactivate!
88
+ end
89
+
90
+ it "should raise an error if the sequence file is missing" do
91
+ settings = mock_command_line_settings(@scaffold_file,@missing_file)
92
+ tool = Scaffolder::Tool.new(settings)
93
+ lambda{ tool.scaffold }.should raise_error(ArgumentError,
94
+ "Sequence file not found: #{@missing_file}")
95
+ end
96
+
97
+ it "should raise an error if the sequence file is empty" do
98
+ settings = mock_command_line_settings(@scaffold_file,@empty_file)
99
+ tool = Scaffolder::Tool.new(settings)
100
+ lambda{ tool.scaffold }.should raise_error(ArgumentError,
101
+ "Sequence file is empty: #{@empty_file}")
102
+ end
103
+
104
+ it "should raise an error if the scaffold file is missing" do
105
+ settings = mock_command_line_settings(@missing_file,@sequence_file)
106
+ tool = Scaffolder::Tool.new(settings)
107
+ lambda{ tool.scaffold }.should raise_error(ArgumentError,
108
+ "Scaffold file not found: #{@missing_file}")
109
+ end
110
+
111
+ it "should raise an error if the scaffold file is empty" do
112
+ settings = mock_command_line_settings(@empty_file,@sequence_file)
113
+ tool = Scaffolder::Tool.new(settings)
114
+ lambda{ tool.scaffold }.should raise_error(ArgumentError,
115
+ "Scaffold file is empty: #{@empty_file}")
116
+ end
117
+ end
118
+
119
+ describe "creating the scaffold with the scaffold method" do
120
+
121
+ before(:each) do
122
+ entries = [{:name => 'seq1', :nucleotides => 'ATGC'}]
123
+
124
+ @scaffold_file = File.new('scaffold','w').path
125
+ @sequence_file = File.new('sequence','w').path
126
+ write_scaffold_file(entries,@scaffold_file)
127
+ write_sequence_file(entries,@sequence_file)
128
+ end
129
+
130
+ after(:each) do
131
+ File.delete @scaffold_file, @sequence_file
132
+ end
133
+
134
+ subject do
135
+ Scaffolder::Tool.new(
136
+ mock_command_line_settings(@scaffold_file,@sequence_file))
137
+ end
138
+
139
+ it "should produce the expected sequence scaffold" do
140
+ subject.scaffold.length.should == 1
141
+ subject.scaffold.first.entry_type.should == :sequence
142
+ subject.scaffold.first.sequence.should == 'ATGC'
143
+ end
144
+
145
+ end
146
+
147
+ end
@@ -0,0 +1,51 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'tempfile'
5
+ require 'ostruct'
6
+
7
+ require 'hashie'
8
+ require 'rspec'
9
+ require 'fakefs/safe'
10
+ require 'mocha'
11
+ require 'bio'
12
+ require 'scaffolder/test/helpers'
13
+ require 'scaffolder'
14
+
15
+ require 'scaffolder/tool'
16
+ require 'scaffolder/tool_index'
17
+ require 'scaffolder/binary_helper'
18
+ Dir["#{File.dirname(__FILE__)}/../lib/scaffolder/tool/*.rb"].each do |f|
19
+ require File.expand_path(f)
20
+ end
21
+
22
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
23
+ require File.expand_path(f)
24
+ end
25
+
26
+ RSpec.configure do |config|
27
+ config.mock_with :mocha
28
+
29
+ include Scaffolder::Test::Helpers
30
+
31
+ def tool_subclasses
32
+ ObjectSpace.each_object.map{|obj| obj.class }.select do |cls|
33
+ cls.superclass == Scaffolder::Tool
34
+ end
35
+ end
36
+
37
+ def mock_command_line_settings(scaf_file = mock, seq_file = mock, hash_args={})
38
+ settings = mock
39
+
40
+ settings.stubs(:rest).returns([scaf_file,seq_file])
41
+ settings.stubs(:sequence_file).returns(seq_file)
42
+ settings.stubs(:scaffold_file).returns(scaf_file)
43
+
44
+ hash_args.each do |key,value|
45
+ settings.expects(:[]).with(key).returns(value)
46
+ end
47
+
48
+ settings
49
+ end
50
+
51
+ end
@@ -0,0 +1,26 @@
1
+ # See: How can I validate exits and aborts in RSpec?
2
+ # http://stackoverflow.com/questions/1480537
3
+
4
+ module ExitCodeMatchers
5
+ RSpec::Matchers.define :exit_with_code do |code|
6
+ actual = nil
7
+ match do |block|
8
+ begin
9
+ block.call
10
+ rescue SystemExit => e
11
+ actual = e.status
12
+ end
13
+ actual and actual == code
14
+ end
15
+ failure_message_for_should do |block|
16
+ "expected block to call exit(#{code}) but exit" +
17
+ (actual.nil? ? " not called" : "(#{actual}) was called")
18
+ end
19
+ failure_message_for_should_not do |block|
20
+ "expected block not to call exit(#{code})"
21
+ end
22
+ description do
23
+ "expect block to call exit(#{code})"
24
+ end
25
+ end
26
+ end