hglib 0.1.pre20180129173049 → 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
- checksums.yaml.gz.sig +3 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +94 -11
- data/History.md +1 -1
- data/Manifest.txt +12 -0
- data/Rakefile +1 -1
- data/examples/clone.rb +13 -0
- data/integration/commands/clone_spec.rb +52 -0
- data/integration/spec_helper.rb +29 -0
- data/lib/hglib.rb +7 -7
- data/lib/hglib/repo.rb +129 -0
- data/lib/hglib/repo/id.rb +81 -0
- data/lib/hglib/repo/log_entry.rb +128 -0
- data/lib/hglib/server.rb +320 -0
- data/spec/.status +39 -0
- data/spec/hglib/repo/id_spec.rb +182 -0
- data/spec/hglib/repo/log_entry_spec.rb +69 -0
- data/spec/hglib/repo_spec.rb +106 -0
- data/spec/hglib/server_spec.rb +166 -0
- data/spec/spec_helper.rb +6 -1
- metadata +44 -34
- metadata.gz.sig +0 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/repo/id'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib::Repo::Id do
|
9
|
+
|
10
|
+
it "can be created for an empty repo" do
|
11
|
+
result = described_class.new( '000000000000', 'tip' )
|
12
|
+
|
13
|
+
expect( result.global ).to eq( '000000000000' )
|
14
|
+
expect( result ).to eq( '000000000000' )
|
15
|
+
expect( result.tags ).to contain_exactly( 'tip' )
|
16
|
+
expect( result.bookmarks ).to be_empty
|
17
|
+
expect( result ).to_not have_uncommitted_changes
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
it "can be created for a repo with commits" do
|
22
|
+
result = described_class.new( 'd03a659966ec', 'tip' )
|
23
|
+
|
24
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
25
|
+
expect( result ).to eq( 'd03a659966ec' )
|
26
|
+
expect( result.tags ).to contain_exactly( 'tip' )
|
27
|
+
expect( result.bookmarks ).to be_empty
|
28
|
+
expect( result ).to_not have_uncommitted_changes
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it "can be created for a repo with uncommitted changes" do
|
33
|
+
result = described_class.new( 'd03a659966ec', 'tip', uncommitted_changes: true )
|
34
|
+
|
35
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
36
|
+
expect( result ).to have_uncommitted_changes
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "can be created for a repo with more than one tag" do
|
41
|
+
result = described_class.new( 'd03a659966ec', 'qbase', 'qtip', 'repo-features.patch', 'tip' )
|
42
|
+
|
43
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
44
|
+
expect( result.tags ).to contain_exactly( 'qbase', 'qtip', 'repo-features.patch', 'tip' )
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
it "can be created for a repo with a bookmark" do
|
49
|
+
result = described_class.new( 'd03a659966ec', 'tip', bookmarks: 'master' )
|
50
|
+
|
51
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
52
|
+
expect( result.bookmarks ).to contain_exactly( 'master' )
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
it "can be created for a repo with more than one bookmark" do
|
57
|
+
result = described_class.new( 'd03a659966ec', 'tip', bookmarks: ['master', 'github/master'] )
|
58
|
+
|
59
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
60
|
+
expect( result.bookmarks ).to contain_exactly( 'master', 'github/master' )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
describe "equality" do
|
65
|
+
|
66
|
+
it "is equal to an object of the same class with the same values" do
|
67
|
+
id = described_class.new( 'd03a659966ec',
|
68
|
+
'qbase', 'qtip', 'repo-features.patch', 'tip',
|
69
|
+
uncommitted_changes: true,
|
70
|
+
bookmarks: ['master', 'live']
|
71
|
+
)
|
72
|
+
|
73
|
+
copy = id.dup
|
74
|
+
|
75
|
+
expect( id ).to eq( copy )
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
it "is equal to the String that contains the same revision identifier" do
|
80
|
+
id = described_class.new( 'd03a659966ec',
|
81
|
+
'qbase', 'qtip', 'repo-features.patch', 'tip',
|
82
|
+
uncommitted_changes: true,
|
83
|
+
bookmarks: ['master', 'live']
|
84
|
+
)
|
85
|
+
|
86
|
+
expect( id ).to eq( 'd03a659966ec' )
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
describe "parsing server output" do
|
93
|
+
|
94
|
+
it "can parse the server output from an empty repo" do
|
95
|
+
result = described_class.parse( '000000000000 tip' )
|
96
|
+
|
97
|
+
expect( result.global ).to eq( '000000000000' )
|
98
|
+
expect( result ).to eq( '000000000000' )
|
99
|
+
expect( result.tags ).to contain_exactly( 'tip' )
|
100
|
+
expect( result.bookmarks ).to be_empty
|
101
|
+
expect( result ).to_not have_uncommitted_changes
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
it "can be parsed from the server output from a repo with commits" do
|
106
|
+
result = described_class.parse( 'd03a659966ec tip' )
|
107
|
+
|
108
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
109
|
+
expect( result ).to eq( 'd03a659966ec' )
|
110
|
+
expect( result.tags ).to contain_exactly( 'tip' )
|
111
|
+
expect( result.bookmarks ).to be_empty
|
112
|
+
expect( result ).to_not have_uncommitted_changes
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
it "can be parsed from the server output from a repo with uncommitted changes" do
|
117
|
+
result = described_class.parse( 'd03a659966ec+ tip' )
|
118
|
+
|
119
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
120
|
+
expect( result ).to have_uncommitted_changes
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
it "can be parsed from the server output from a repo with more than one tag" do
|
125
|
+
result = described_class.parse( 'd03a659966ec qbase/qtip/repo-features.patch/tip' )
|
126
|
+
|
127
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
128
|
+
expect( result.tags ).to contain_exactly( 'qbase', 'qtip', 'repo-features.patch', 'tip' )
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
it "can be parsed from the server output from a repo with a bookmark" do
|
133
|
+
result = described_class.parse( 'd03a659966ec tip master' )
|
134
|
+
|
135
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
136
|
+
expect( result.bookmarks ).to contain_exactly( 'master' )
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
it "can be parsed from the server output from a repo with more than one bookmark" do
|
141
|
+
result = described_class.parse( 'd03a659966ec tip master/servant' )
|
142
|
+
|
143
|
+
expect( result.global ).to eq( 'd03a659966ec' )
|
144
|
+
expect( result.bookmarks ).to contain_exactly( 'master', 'servant' )
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
describe "stringifying" do
|
151
|
+
|
152
|
+
it "works for the ID of an empty repo" do
|
153
|
+
id = described_class.new( '000000000000', 'tip' )
|
154
|
+
|
155
|
+
expect( id.to_s ).to eq( '000000000000 tip' )
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
it "works for the ID of a repo with uncommitted changes" do
|
160
|
+
id = described_class.new( 'd03a659966ec', 'tip', uncommitted_changes: true )
|
161
|
+
|
162
|
+
expect( id.to_s ).to eq( 'd03a659966ec+ tip' )
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
it "works for the ID of a repo with more than one tag" do
|
167
|
+
id = described_class.new( 'd03a659966ec', 'qbase', 'qtip', 'repo-features.patch', 'tip' )
|
168
|
+
|
169
|
+
expect( id.to_s ).to eq( 'd03a659966ec qbase/qtip/repo-features.patch/tip' )
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
it "works for the ID of a repo with a bookmark" do
|
174
|
+
id = described_class.new( 'd03a659966ec', 'tip', bookmarks: 'master' )
|
175
|
+
|
176
|
+
expect( id.to_s ).to eq( 'd03a659966ec tip master' )
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative '../../spec_helper'
|
5
|
+
|
6
|
+
require 'hglib/repo/log_entry'
|
7
|
+
|
8
|
+
|
9
|
+
RSpec.describe Hglib::Repo::LogEntry do
|
10
|
+
|
11
|
+
RAW_LOG_ENTRY = {
|
12
|
+
"bookmarks" => ['master'],
|
13
|
+
"branch" => "default",
|
14
|
+
"date" => [1526420446, 25200],
|
15
|
+
"desc" => "Flesh out the features of Repo objects",
|
16
|
+
"node" => "d4af915821dea2feca29288dc16742c0d41cee8c",
|
17
|
+
"parents" => ["a366819bd05b8dd995440105340e057528be25e6"],
|
18
|
+
"phase" => "public",
|
19
|
+
"rev" => 5,
|
20
|
+
"tags" => ['github/master', 'tip'],
|
21
|
+
"user" => "Michael Granger <ged@FaerieMUD.org>"
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
VERBOSE_LOG_ENTRY = RAW_LOG_ENTRY.merge(
|
25
|
+
"files" => %w[.hoerc .ruby-version lib/hglib/repo.rb spec/hglib/repo_spec.rb]
|
26
|
+
).freeze
|
27
|
+
|
28
|
+
|
29
|
+
it "can be created from the JSON log hash" do
|
30
|
+
entry = described_class.new( RAW_LOG_ENTRY )
|
31
|
+
|
32
|
+
expected_time = Time.parse( 'Tue May 15 14:40:46 2018 -0700' )
|
33
|
+
|
34
|
+
expect( entry ).to be_a( described_class )
|
35
|
+
expect( entry.changeset ).to eq( '5:d4af915821de' )
|
36
|
+
expect( entry.rev ).to eq( 5 )
|
37
|
+
expect( entry.node ).to eq( 'd4af915821dea2feca29288dc16742c0d41cee8c' )
|
38
|
+
expect( entry.bookmarks ).to contain_exactly( 'master' )
|
39
|
+
expect( entry.tags ).to contain_exactly( 'github/master', 'tip' )
|
40
|
+
expect( entry.user ).to eq( 'Michael Granger <ged@FaerieMUD.org>' )
|
41
|
+
expect( entry.date ).to be_a( Time ).and( eq(expected_time) )
|
42
|
+
expect( entry.summary ).to eq( 'Flesh out the features of Repo objects' )
|
43
|
+
|
44
|
+
expect( entry.diff ).to be_nil
|
45
|
+
expect( entry.files ).to be_empty
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "can be created from verbose log entry JSON" do
|
50
|
+
entry = described_class.new( VERBOSE_LOG_ENTRY )
|
51
|
+
|
52
|
+
expected_time = Time.parse( 'Tue May 15 14:40:46 2018 -0700' )
|
53
|
+
|
54
|
+
expect( entry ).to be_a( described_class )
|
55
|
+
expect( entry.changeset ).to eq( '5:d4af915821de' )
|
56
|
+
expect( entry.rev ).to eq( 5 )
|
57
|
+
expect( entry.node ).to eq( 'd4af915821dea2feca29288dc16742c0d41cee8c' )
|
58
|
+
expect( entry.bookmarks ).to contain_exactly( 'master' )
|
59
|
+
expect( entry.tags ).to contain_exactly( 'github/master', 'tip' )
|
60
|
+
expect( entry.user ).to eq( 'Michael Granger <ged@FaerieMUD.org>' )
|
61
|
+
expect( entry.date ).to be_a( Time ).and( eq(expected_time) )
|
62
|
+
expect( entry.summary ).to eq( 'Flesh out the features of Repo objects' )
|
63
|
+
|
64
|
+
expect( entry.diff ).to be_nil
|
65
|
+
expect( entry.files ).to contain_exactly( *VERBOSE_LOG_ENTRY['files'] )
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/repo'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib::Repo do
|
9
|
+
|
10
|
+
let( :repo_dir ) do
|
11
|
+
Dir.mktmpdir( ['hglib', 'repodir'] )
|
12
|
+
end
|
13
|
+
|
14
|
+
let( :server ) { instance_double(Hglib::Server) }
|
15
|
+
|
16
|
+
|
17
|
+
before( :each ) do
|
18
|
+
allow( Hglib::Server ).to receive( :new ).and_return( server )
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it "can fetch the status of the working directory" do
|
23
|
+
repo = described_class.new( repo_dir )
|
24
|
+
|
25
|
+
expect( server ).to receive( :run ).with( :status, {} ).
|
26
|
+
and_return([
|
27
|
+
"M ",
|
28
|
+
".gems\n",
|
29
|
+
"M ",
|
30
|
+
"lib/hglib/repo.rb\n",
|
31
|
+
"M ",
|
32
|
+
"lib/hglib/server.rb\n",
|
33
|
+
"? ",
|
34
|
+
"coverage/assets/0.10.2/magnify.png\n"
|
35
|
+
])
|
36
|
+
|
37
|
+
result = repo.status
|
38
|
+
|
39
|
+
expect( result ).to be_a( Hash )
|
40
|
+
expect( result ).to include(
|
41
|
+
Pathname('.gems') => 'M',
|
42
|
+
Pathname('lib/hglib/repo.rb') => 'M',
|
43
|
+
Pathname('lib/hglib/server.rb') => 'M',
|
44
|
+
Pathname('coverage/assets/0.10.2/magnify.png') => '?'
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "can fetch the identification of the repository's current revision" do
|
50
|
+
repo = described_class.new( repo_dir )
|
51
|
+
|
52
|
+
expect( server ).to receive( :run ).with( :id, {} ).
|
53
|
+
and_return( ["80d775fc1d2c+ qbase/qtip/repo-features.patch/tip master\n"] )
|
54
|
+
|
55
|
+
result = repo.id
|
56
|
+
|
57
|
+
expect( result ).to be_a( Hglib::Repo::Id ).and( eq '80d775fc1d2c' )
|
58
|
+
expect( result.tags ).to eq( %w[qbase qtip repo-features.patch tip] )
|
59
|
+
expect( result.bookmarks ).to eq( %w[master] )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it "can fetch the log of the repository" do
|
64
|
+
repo = described_class.new( repo_dir )
|
65
|
+
|
66
|
+
expect( server ).to receive( :run ).with( :log, {T: 'json', graph: false} ).
|
67
|
+
and_return([
|
68
|
+
"[",
|
69
|
+
"\n {\n \"bookmarks\": [],\n \"branch\": \"default\",\n \"date\": " +
|
70
|
+
"[1516812073, 28800],\n \"desc\": \"Make ruby-version less specific\"," +
|
71
|
+
"\n \"node\": \"81f357f730d9f22d560e4bd2790e7cf5aa5b7ec7\",\n \"parents\":" +
|
72
|
+
" [\"d6c97f99b012199d9088e85bb0940147446c6a87\"],\n \"phase\": \"public\",\n " +
|
73
|
+
" \"rev\": 1,\n \"tags\": [],\n \"user\": \"Michael Granger" +
|
74
|
+
" <ged@FaerieMUD.org>\"\n }",
|
75
|
+
",",
|
76
|
+
"\n {\n",
|
77
|
+
" \"bookmarks\": []",
|
78
|
+
",\n",
|
79
|
+
" \"branch\": \"default\"",
|
80
|
+
",\n",
|
81
|
+
" \"date\": [1516811121, 28800]",
|
82
|
+
",\n",
|
83
|
+
" \"desc\": \"Initial commit.\"",
|
84
|
+
",\n",
|
85
|
+
" \"node\": \"d6c97f99b012199d9088e85bb0940147446c6a87\"",
|
86
|
+
",\n",
|
87
|
+
" \"parents\": [\"0000000000000000000000000000000000000000\"]",
|
88
|
+
",\n",
|
89
|
+
" \"phase\": \"public\"",
|
90
|
+
",\n",
|
91
|
+
" \"rev\": 0",
|
92
|
+
",\n",
|
93
|
+
" \"tags\": []",
|
94
|
+
",\n",
|
95
|
+
" \"user\": \"Michael Granger <ged@FaerieMUD.org>\"",
|
96
|
+
"\n }",
|
97
|
+
"\n]\n"
|
98
|
+
])
|
99
|
+
|
100
|
+
result = repo.log
|
101
|
+
|
102
|
+
expect( result ).to be_an( Array ).and( all be_a(Hglib::Repo::LogEntry) )
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'tmpdir'
|
6
|
+
require 'hglib/server'
|
7
|
+
|
8
|
+
|
9
|
+
RSpec.describe Hglib::Server do
|
10
|
+
|
11
|
+
def cmdserver_message( channel, data='' )
|
12
|
+
return [ channel, data.bytesize, data ].pack( 'A*I>A*' )
|
13
|
+
end
|
14
|
+
|
15
|
+
def cmdserver_header( channel, bytes )
|
16
|
+
return [ channel, bytes ].pack( 'aI>' )
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
let( :repo_dir ) do
|
21
|
+
Dir.mktmpdir( ['hglib', 'repodir'] )
|
22
|
+
end
|
23
|
+
|
24
|
+
let( :parent_reader ) { StringIO.new }
|
25
|
+
let( :child_reader ) { instance_double(IO, close: true) }
|
26
|
+
let( :parent_writer ) { StringIO.new }
|
27
|
+
let( :child_writer ) { instance_double(IO, close: true) }
|
28
|
+
|
29
|
+
let( :hello_message ) do
|
30
|
+
cmdserver_message( 'o', "capabilities: runcommand getencoding\nencoding: UTF-8\n" )
|
31
|
+
end
|
32
|
+
let( :line_input_prompt ) do
|
33
|
+
cmdserver_header( 'L', 4096 )
|
34
|
+
end
|
35
|
+
let( :byte_input_prompt ) do
|
36
|
+
cmdserver_header( 'I', 4096 )
|
37
|
+
end
|
38
|
+
let( :result_message ) do
|
39
|
+
cmdserver_message( 'r', "done" )
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
before( :each ) do
|
44
|
+
allow( Process ).to receive( :spawn ).and_return( 1111 )
|
45
|
+
allow( Process ).to receive( :kill ).with( :TERM, 1111 )
|
46
|
+
allow( Process ).to receive( :wait ).with( 1111, Process::WNOHANG )
|
47
|
+
|
48
|
+
allow( IO ).to receive( :pipe ).and_return(
|
49
|
+
[parent_reader, child_writer],
|
50
|
+
[child_reader, parent_writer]
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe "option-mangling" do
|
56
|
+
|
57
|
+
it "mangles single-letter keys into one-hyphen options" do
|
58
|
+
result = described_class.mangle_options( C: true, p: true, g: true )
|
59
|
+
expect( result ).to eq( %w[-C -p -g] )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it "mangles multi-letter keys into two-hyphen options" do
|
64
|
+
result = described_class.mangle_options( copies: true, patch: true )
|
65
|
+
expect( result ).to eq( %w[--copies --patch] )
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
it "drops single-letter keys with falsey values" do
|
70
|
+
result = described_class.mangle_options( g: false, p: nil )
|
71
|
+
expect( result ).to eq( [] )
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
it "negates multi-letter keys with falsey values" do
|
76
|
+
result = described_class.mangle_options( graph: false, patch: nil )
|
77
|
+
expect( result ).to eq( %w[--no-graph --no-patch] )
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
it "appends String values onto options with a space for single-letter keys" do
|
82
|
+
result = described_class.mangle_options( P: '165' )
|
83
|
+
expect( result ).to eq( %w[-P 165] )
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
it "appends String values onto options with an equal for multi-letter keys" do
|
88
|
+
result = described_class.mangle_options( prune: '165' )
|
89
|
+
expect( result ).to eq( %w[--prune=165] )
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
it "knows whether or not it has been started" do
|
96
|
+
parent_reader.write( hello_message )
|
97
|
+
parent_reader.rewind
|
98
|
+
|
99
|
+
server = described_class.new( repo_dir )
|
100
|
+
|
101
|
+
expect( server ).to_not be_started
|
102
|
+
server.start
|
103
|
+
expect( server ).to be_started
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
it "calls the on_line_input callback when the command server asks for line input" do
|
108
|
+
parent_reader.write( hello_message )
|
109
|
+
parent_reader.write( line_input_prompt )
|
110
|
+
parent_reader.write( result_message )
|
111
|
+
parent_reader.rewind
|
112
|
+
|
113
|
+
server = described_class.new( repo_dir )
|
114
|
+
server.on_line_input do |max_bytes|
|
115
|
+
"a line of input no more than #{max_bytes} long"
|
116
|
+
end
|
117
|
+
server.run( :record )
|
118
|
+
|
119
|
+
expect( parent_writer.string ).to include(
|
120
|
+
"runcommand\n",
|
121
|
+
"record",
|
122
|
+
"a line of input no more than 4096 long\n"
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
it "calls the on_byte_input callback when the command server asks for byte input" do
|
128
|
+
parent_reader.write( hello_message )
|
129
|
+
parent_reader.write( byte_input_prompt )
|
130
|
+
parent_reader.write( result_message )
|
131
|
+
parent_reader.rewind
|
132
|
+
|
133
|
+
server = described_class.new( repo_dir )
|
134
|
+
server.on_byte_input do |max_bytes|
|
135
|
+
"bytes of input no more than #{max_bytes} long"
|
136
|
+
end
|
137
|
+
server.run( :import, '-' )
|
138
|
+
|
139
|
+
expect( parent_writer.string ).to include(
|
140
|
+
"runcommand\n",
|
141
|
+
"import\0-",
|
142
|
+
"bytes of input no more than 4096 long"
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
it "can be stopped manually" do
|
148
|
+
parent_reader.write( hello_message )
|
149
|
+
parent_reader.rewind
|
150
|
+
|
151
|
+
server = described_class.new( repo_dir )
|
152
|
+
server.start
|
153
|
+
|
154
|
+
server.stop
|
155
|
+
expect( parent_writer.string ).to be_empty
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
it "doesn't error when told to stop if it hasn't been started" do
|
160
|
+
server = described_class.new( repo_dir )
|
161
|
+
expect( server.stop ).to be_falsey
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
end
|
166
|
+
|