neovim 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,7 @@ require "tempfile"
4
4
  module Neovim
5
5
  RSpec.describe Host do
6
6
  describe ".load_from_files" do
7
- it "loads the defined plugins" do
7
+ it "loads the defined plugins into a manifest" do
8
8
  plug1 = Tempfile.open("plug1") do |f|
9
9
  f.write("Neovim.plugin")
10
10
  f.path
@@ -15,8 +15,11 @@ module Neovim
15
15
  f.path
16
16
  end
17
17
 
18
- host = Host.load_from_files([plug1, plug2])
19
- expect(host.plugins.size).to eq(3)
18
+ manifest = Manifest.new
19
+
20
+ expect(manifest).to receive(:register).exactly(3).times
21
+ host = Host.load_from_files([plug1, plug2], manifest)
22
+ expect(host.manifest).to eq(manifest)
20
23
  end
21
24
 
22
25
  it "doesn't load plugin code into the global namespace" do
@@ -31,49 +34,7 @@ module Neovim
31
34
  end
32
35
 
33
36
  describe "#run" do
34
- it "runs an async client with the plugins as callbacks" do
35
- sync_cb = lambda { |nvim, x, y| [nvim, x, y] }
36
- async_cb = lambda { |nvim, x, y| [nvim, x, y] }
37
-
38
- plugin = Plugin.from_config_block do |plug|
39
- plug.command(:Sync, :nargs => 2, :sync => true, &sync_cb)
40
- plug.command(:Async, :nargs => 2, &async_cb)
41
- end
42
-
43
- mock_async_session = double(:async_session, :request => nil)
44
- expect(AsyncSession).to receive(:new) { mock_async_session }
45
-
46
- mock_client = double(:client)
47
- expect(Client).to receive(:new) { mock_client }
48
-
49
- expect(EventLoop).to receive(:stdio) { double(:event_loop) }
50
- expect(MsgpackStream).to receive(:new) { double(:msgpack_stream) }
51
- expect(Session).to receive(:new) { double(:session) }
52
-
53
- expect(mock_async_session).to receive(:run) do |req_cb, not_cb|
54
- mock_request = double(
55
- :request,
56
- :method_name => :Sync,
57
- :arguments => [1, 2]
58
- )
59
-
60
- mock_notification = double(
61
- :notification,
62
- :method_name => :Async,
63
- :arguments => [3, 4]
64
- )
65
-
66
- expect(sync_cb).to receive(:call).with(mock_client, 1, 2).and_call_original
67
- expect(mock_request).to receive(:respond).with([mock_client, 1, 2])
68
- req_cb.call(mock_request)
69
-
70
- expect(async_cb).to receive(:call).with(mock_client, 3, 4).and_call_original
71
- not_cb.call(mock_notification)
72
- end
73
-
74
- host = Host.new([plugin])
75
- host.run
76
- end
37
+ # TODO: Find a way to test this without excessive mocking
77
38
  end
78
39
  end
79
40
  end
@@ -0,0 +1,68 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe LineRange do
5
+ let(:client) { Neovim.attach_child(["--headless", "-n", "-u", "NONE"]) }
6
+ let(:buffer) { client.current.buffer }
7
+ let(:line_range) { LineRange.new(buffer, 0, -1) }
8
+
9
+ before do
10
+ client.command("normal i1")
11
+ client.command("normal o2")
12
+ client.command("normal o3")
13
+ end
14
+
15
+ it "is enumerable" do
16
+ expect(line_range).to be_an(Enumerable)
17
+ expect(line_range).to respond_to(:each)
18
+ end
19
+
20
+ describe "#to_a" do
21
+ it "returns lines as an array" do
22
+ expect(line_range.to_a).to eq(["1", "2", "3"])
23
+ end
24
+ end
25
+
26
+ describe "#[]" do
27
+ it "accepts a single index" do
28
+ expect(line_range[1]).to eq("2")
29
+ end
30
+
31
+ it "accepts an index and length" do
32
+ expect(line_range[0, 2].to_a).to eq(["1", "2"])
33
+ end
34
+
35
+ it "accepts a range" do
36
+ expect(line_range[0..1].to_a).to eq(["1", "2"])
37
+ expect(line_range[0...1].to_a).to eq(["1"])
38
+ end
39
+ end
40
+
41
+ describe "#[]=" do
42
+ it "accepts a single index" do
43
+ line_range[0] = "foo"
44
+ expect(line_range.to_a).to eq(["foo", "2", "3"])
45
+ end
46
+
47
+ it "accepts an index and length" do
48
+ line_range[0, 2] = ["foo"]
49
+ expect(line_range.to_a).to eq(["foo", "3"])
50
+ end
51
+
52
+ it "accepts a range" do
53
+ line_range[0..1] = ["foo"]
54
+ expect(line_range.to_a).to eq(["foo", "3"])
55
+
56
+ line_range[0...1] = ["bar"]
57
+ expect(line_range.to_a).to eq(["bar", "3"])
58
+ end
59
+ end
60
+
61
+ describe "#replace" do
62
+ it "replaces all lines" do
63
+ line_range.replace(["5", "6"])
64
+ expect(line_range.to_a).to eq(["5", "6"])
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,113 @@
1
+ require "helper"
2
+ require "neovim/manifest"
3
+ require "neovim/plugin"
4
+
5
+ module Neovim
6
+ RSpec.describe Manifest do
7
+ it "has a default poll handler" do
8
+ manifest = Manifest.new
9
+ expect(manifest.handlers["poll"]).to respond_to(:call)
10
+ end
11
+
12
+ it "has default specs" do
13
+ manifest = Manifest.new
14
+ expect(manifest.specs).to eq({})
15
+ end
16
+
17
+ describe "#register" do
18
+ it "adds specs" do
19
+ manifest = Manifest.new
20
+
21
+ plugin = Plugin.from_config_block("source") do |plug|
22
+ plug.command(:Foo)
23
+ end
24
+
25
+ expect {
26
+ manifest.register(plugin)
27
+ }.to change { manifest.specs }.from({}).to("source" => plugin.specs)
28
+ end
29
+
30
+ it "adds plugin handlers" do
31
+ manifest = Manifest.new
32
+
33
+ plugin = Plugin.from_config_block("source") do |plug|
34
+ plug.command(:Foo)
35
+ end
36
+
37
+ expect {
38
+ manifest.register(plugin)
39
+ }.to change {
40
+ manifest.handlers["source:command:Foo"]
41
+ }.from(nil).to(kind_of(Proc))
42
+ end
43
+ end
44
+
45
+ describe "#handle" do
46
+ it "calls the poll handler" do
47
+ manifest = Manifest.new
48
+ message = double(:message, :method_name => "poll", :sync? => true)
49
+ client = double(:client)
50
+
51
+ expect(message).to receive(:respond).with("ok")
52
+ manifest.handle(message, client)
53
+ end
54
+
55
+ it "calls the specs handler" do
56
+ manifest = Manifest.new
57
+ plugin = Plugin.from_config_block("source") do |plug|
58
+ plug.command(:Foo)
59
+ end
60
+ manifest.register(plugin)
61
+
62
+ message = double(:message, :method_name => "specs", :sync? => true, :arguments => ["source"])
63
+
64
+ expect(message).to receive(:respond).with(plugin.specs)
65
+ manifest.handle(message, double(:client))
66
+ end
67
+
68
+ it "calls a plugin sync handler" do
69
+ manifest = Manifest.new
70
+ plugin = Plugin.from_config_block("source") do |plug|
71
+ plug.command(:Foo, :sync => true) { |client, arg| [client, arg] }
72
+ end
73
+ manifest.register(plugin)
74
+
75
+ message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [:arg])
76
+ client = double(:client)
77
+
78
+ expect(message).to receive(:respond).with([client, :arg])
79
+ manifest.handle(message, client)
80
+ end
81
+
82
+ it "calls a plugin async handler" do
83
+ manifest = Manifest.new
84
+ async_proc = Proc.new {}
85
+ plugin = Plugin.from_config_block("source") do |plug|
86
+ plug.command(:Foo, &async_proc)
87
+ end
88
+ manifest.register(plugin)
89
+
90
+ message = double(:message, :method_name => "source:command:Foo", :sync? => false, :arguments => [:arg])
91
+ client = double(:client)
92
+
93
+ expect(async_proc).to receive(:call).with(client, :arg)
94
+ manifest.handle(message, client)
95
+ end
96
+
97
+ it "calls a default sync handler" do
98
+ manifest = Manifest.new
99
+ message = double(:message, :method_name => "foobar", :sync? => true)
100
+
101
+ expect(message).to receive(:error).with("Unknown request foobar")
102
+ manifest.handle(message, double(:client))
103
+ end
104
+
105
+ it "calls a default async handler" do
106
+ manifest = Manifest.new
107
+ message = double(:message, :method_name => "foobar", :sync? => false)
108
+
109
+ manifest.handle(message, double(:client))
110
+ end
111
+ end
112
+ end
113
+ end
@@ -11,13 +11,15 @@ module Neovim
11
11
  srv_thr = Thread.new do
12
12
  client = server.accept
13
13
  messages << client.readpartial(1024)
14
+
14
15
  client.write(MessagePack.pack([2]))
16
+ client.close
17
+ server.close
15
18
  end
16
19
 
17
20
  fiber = Fiber.new do
18
- stream.send([1]).run do |msg|
19
- Fiber.yield(msg)
20
- end
21
+ msg_cb = Proc.new { |msg| Fiber.yield(msg) }
22
+ stream.send([1]).run(msg_cb)
21
23
  end
22
24
 
23
25
  expect(fiber.resume).to eq([2])
@@ -6,60 +6,60 @@ module Neovim
6
6
  it "registers a command" do
7
7
  cmd_block = Proc.new {}
8
8
 
9
- plugin = Plugin.from_config_block do |plug|
9
+ plugin = Plugin.from_config_block("source") do |plug|
10
10
  plug.command("Foo", :range => true, :nargs => 1, &cmd_block)
11
11
  end
12
12
 
13
- expect(plugin.specs).to eq(
14
- [
15
- {
16
- :type => :command,
17
- :name => :Foo,
18
- :sync => false,
19
- :opts => {:range => "", :nargs => 1},
20
- :proc => cmd_block
21
- }
22
- ]
13
+ expect(plugin.handlers.size).to be(1)
14
+ handler = plugin.handlers.first
15
+
16
+ expect(handler.block).to eq(cmd_block)
17
+ expect(handler.qualified_name).to eq("source:command:Foo")
18
+ expect(handler.to_spec).to eq(
19
+ :type => :command,
20
+ :name => "Foo",
21
+ :sync => false,
22
+ :opts => {:range => "", :nargs => 1},
23
23
  )
24
24
  end
25
25
 
26
26
  it "registers an autocmd" do
27
27
  au_block = Proc.new {}
28
28
 
29
- plugin = Plugin.from_config_block do |plug|
29
+ plugin = Plugin.from_config_block("source") do |plug|
30
30
  plug.autocmd("BufEnter", :pattern => "*.rb", &au_block)
31
31
  end
32
32
 
33
- expect(plugin.specs).to eq(
34
- [
35
- {
36
- :type => :autocmd,
37
- :name => :BufEnter,
38
- :sync => false,
39
- :opts => {:pattern => "*.rb"},
40
- :proc => au_block
41
- }
42
- ]
33
+ expect(plugin.handlers.size).to be(1)
34
+ handler = plugin.handlers.first
35
+
36
+ expect(handler.block).to eq(au_block)
37
+ expect(handler.qualified_name).to eq("source:autocmd:BufEnter:*.rb")
38
+ expect(handler.to_spec).to eq(
39
+ :type => :autocmd,
40
+ :name => "BufEnter",
41
+ :sync => false,
42
+ :opts => {:pattern => "*.rb"},
43
43
  )
44
44
  end
45
45
 
46
46
  it "registers a function" do
47
47
  fun_block = Proc.new {}
48
48
 
49
- plugin = Plugin.from_config_block do |plug|
49
+ plugin = Plugin.from_config_block("source") do |plug|
50
50
  plug.function("Foo", :range => true, :nargs => 1, &fun_block)
51
51
  end
52
52
 
53
- expect(plugin.specs).to eq(
54
- [
55
- {
56
- :type => :function,
57
- :name => :Foo,
58
- :sync => false,
59
- :opts => {:range => "", :nargs => 1},
60
- :proc => fun_block
61
- }
62
- ]
53
+ expect(plugin.handlers.size).to be(1)
54
+ handler = plugin.handlers.first
55
+
56
+ expect(handler.block).to eq(fun_block)
57
+ expect(handler.qualified_name).to eq("source:function:Foo")
58
+ expect(handler.to_spec).to eq(
59
+ :type => :function,
60
+ :name => "Foo",
61
+ :sync => false,
62
+ :opts => {:range => "", :nargs => 1},
63
63
  )
64
64
  end
65
65
  end
@@ -1,33 +1,112 @@
1
1
  require "helper"
2
+ require "securerandom"
3
+ require "fileutils"
2
4
 
3
5
  module Neovim
4
6
  RSpec.describe Session do
5
- let(:session) do
6
- event_loop = EventLoop.child(["-n", "-u", "NONE"])
7
- stream = MsgpackStream.new(event_loop)
8
- async = AsyncSession.new(stream)
9
- Session.new(async)
10
- end
7
+ shared_context "session behavior" do
8
+ it "supports functions with async=false" do
9
+ expect(session.request(:vim_strwidth, "foobar")).to be(6)
10
+ end
11
+
12
+ it "supports functions with async=true" do
13
+ expect(session.request(:vim_input, "jk")).to be(2)
14
+ end
15
+
16
+ it "raises an exception when there are errors" do
17
+ expect {
18
+ session.request(:vim_strwidth, "too", "many")
19
+ }.to raise_error(/wrong number of arguments/i)
20
+ end
11
21
 
12
- it "supports functions with async=false" do
13
- expect(session.request(:vim_strwidth, "foobar")).to be(6)
22
+ it "handles large data" do
23
+ large_str = Array.new(1024 * 16) { SecureRandom.hex(1) }.join
24
+ session.request(:vim_set_current_line, large_str)
25
+ expect(session.request(:vim_get_current_line)).to eq(large_str)
26
+ end
27
+
28
+ describe "#api_methods_for_prefix" do
29
+ it "returns relevant functions without a prefix" do
30
+ methods = session.api_methods_for_prefix("vim_")
31
+ expect(methods).to include(:strwidth)
32
+ end
33
+ end
14
34
  end
15
35
 
16
- it "supports functions with async=true" do
17
- expect(session.request(:vim_input, "jk")).to be(2)
36
+ context "tcp" do
37
+ let!(:nvim_port) do
38
+ server = TCPServer.new("0.0.0.0", 0)
39
+ server.addr[1].tap { server.close }
40
+ end
41
+
42
+ let!(:nvim_pid) do
43
+ Process.spawn(
44
+ {"NVIM_LISTEN_ADDRESS" => "0.0.0.0:#{nvim_port}"},
45
+ "#{ENV.fetch("NVIM_EXECUTABLE")} --headless -n -u NONE",
46
+ [:out, :err] => "/dev/null"
47
+ ).tap do
48
+ begin
49
+ TCPSocket.open("0.0.0.0", nvim_port).close
50
+ rescue Errno::ECONNREFUSED
51
+ retry
52
+ end
53
+ end
54
+ end
55
+
56
+ after do
57
+ Process.kill(:TERM, nvim_pid)
58
+ Process.waitpid(nvim_pid)
59
+ end
60
+
61
+ let(:session) do
62
+ event_loop = EventLoop.tcp("0.0.0.0", nvim_port)
63
+ stream = MsgpackStream.new(event_loop)
64
+ async = AsyncSession.new(stream)
65
+ Session.new(async)
66
+ end
67
+
68
+ include_context "session behavior"
18
69
  end
19
70
 
20
- it "raises an exception when there are errors" do
21
- expect {
22
- session.request(:vim_strwidth, "too", "many")
23
- }.to raise_error(/wrong number of arguments/i)
71
+ context "unix" do
72
+ let!(:nvim_pid) do
73
+ FileUtils.rm_f("/tmp/nvim-#$$.sock")
74
+ Process.spawn(
75
+ {"NVIM_LISTEN_ADDRESS" => "/tmp/nvim-#$$.sock"},
76
+ "#{ENV.fetch("NVIM_EXECUTABLE")} --headless -n -u NONE",
77
+ [:out, :err] => "/dev/null"
78
+ ).tap do
79
+ loop do
80
+ break if File.exists?("/tmp/nvim-#$$.sock")
81
+ end
82
+ end
83
+ end
84
+
85
+ after do
86
+ Process.kill(:TERM, nvim_pid)
87
+ Process.waitpid(nvim_pid)
88
+ FileUtils.rm_f("/tmp/nvim-#$$.sock")
89
+ end
90
+
91
+ let(:session) do
92
+ event_loop = EventLoop.unix("/tmp/nvim-#$$.sock")
93
+ stream = MsgpackStream.new(event_loop)
94
+ async = AsyncSession.new(stream)
95
+ Session.new(async)
96
+ end
97
+
98
+ include_context "session behavior"
24
99
  end
25
100
 
26
- describe "#api_methods_for_prefix" do
27
- it "returns relevant functions without a prefix" do
28
- methods = session.api_methods_for_prefix("vim_")
29
- expect(methods).to include(:strwidth)
101
+ context "child" do
102
+ let(:session) do
103
+ event_loop = EventLoop.child(["-n", "-u", "NONE"])
104
+ stream = MsgpackStream.new(event_loop)
105
+ async = AsyncSession.new(stream)
106
+ Session.new(async)
30
107
  end
108
+
109
+ include_context "session behavior"
31
110
  end
32
111
  end
33
112
  end