logstash-core 2.2.4.snapshot1
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.
Potentially problematic release.
This version of logstash-core might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/lib/logstash-core.rb +1 -0
- data/lib/logstash-core/logstash-core.rb +3 -0
- data/lib/logstash-core/version.rb +8 -0
- data/lib/logstash/agent.rb +391 -0
- data/lib/logstash/codecs/base.rb +50 -0
- data/lib/logstash/config/config_ast.rb +550 -0
- data/lib/logstash/config/cpu_core_strategy.rb +32 -0
- data/lib/logstash/config/defaults.rb +12 -0
- data/lib/logstash/config/file.rb +39 -0
- data/lib/logstash/config/grammar.rb +3503 -0
- data/lib/logstash/config/mixin.rb +518 -0
- data/lib/logstash/config/registry.rb +13 -0
- data/lib/logstash/environment.rb +98 -0
- data/lib/logstash/errors.rb +12 -0
- data/lib/logstash/filters/base.rb +205 -0
- data/lib/logstash/inputs/base.rb +116 -0
- data/lib/logstash/inputs/threadable.rb +18 -0
- data/lib/logstash/java_integration.rb +116 -0
- data/lib/logstash/json.rb +61 -0
- data/lib/logstash/logging.rb +91 -0
- data/lib/logstash/namespace.rb +13 -0
- data/lib/logstash/output_delegator.rb +172 -0
- data/lib/logstash/outputs/base.rb +91 -0
- data/lib/logstash/patches.rb +5 -0
- data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
- data/lib/logstash/patches/cabin.rb +35 -0
- data/lib/logstash/patches/profile_require_calls.rb +47 -0
- data/lib/logstash/patches/rubygems.rb +38 -0
- data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
- data/lib/logstash/pipeline.rb +499 -0
- data/lib/logstash/pipeline_reporter.rb +114 -0
- data/lib/logstash/plugin.rb +120 -0
- data/lib/logstash/program.rb +14 -0
- data/lib/logstash/runner.rb +124 -0
- data/lib/logstash/shutdown_watcher.rb +100 -0
- data/lib/logstash/util.rb +203 -0
- data/lib/logstash/util/buftok.rb +139 -0
- data/lib/logstash/util/charset.rb +35 -0
- data/lib/logstash/util/decorators.rb +52 -0
- data/lib/logstash/util/defaults_printer.rb +31 -0
- data/lib/logstash/util/filetools.rb +186 -0
- data/lib/logstash/util/java_version.rb +66 -0
- data/lib/logstash/util/password.rb +25 -0
- data/lib/logstash/util/plugin_version.rb +56 -0
- data/lib/logstash/util/prctl.rb +10 -0
- data/lib/logstash/util/retryable.rb +40 -0
- data/lib/logstash/util/socket_peer.rb +7 -0
- data/lib/logstash/util/unicode_trimmer.rb +81 -0
- data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
- data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
- data/lib/logstash/version.rb +14 -0
- data/locales/en.yml +204 -0
- data/logstash-core.gemspec +58 -0
- data/spec/conditionals_spec.rb +429 -0
- data/spec/logstash/agent_spec.rb +85 -0
- data/spec/logstash/config/config_ast_spec.rb +146 -0
- data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
- data/spec/logstash/config/defaults_spec.rb +10 -0
- data/spec/logstash/config/mixin_spec.rb +158 -0
- data/spec/logstash/environment_spec.rb +56 -0
- data/spec/logstash/filters/base_spec.rb +251 -0
- data/spec/logstash/inputs/base_spec.rb +74 -0
- data/spec/logstash/java_integration_spec.rb +304 -0
- data/spec/logstash/json_spec.rb +96 -0
- data/spec/logstash/output_delegator_spec.rb +144 -0
- data/spec/logstash/outputs/base_spec.rb +40 -0
- data/spec/logstash/patches_spec.rb +90 -0
- data/spec/logstash/pipeline_reporter_spec.rb +85 -0
- data/spec/logstash/pipeline_spec.rb +455 -0
- data/spec/logstash/plugin_spec.rb +169 -0
- data/spec/logstash/runner_spec.rb +68 -0
- data/spec/logstash/shutdown_watcher_spec.rb +113 -0
- data/spec/logstash/util/buftok_spec.rb +31 -0
- data/spec/logstash/util/charset_spec.rb +74 -0
- data/spec/logstash/util/defaults_printer_spec.rb +50 -0
- data/spec/logstash/util/java_version_spec.rb +79 -0
- data/spec/logstash/util/plugin_version_spec.rb +64 -0
- data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
- data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
- data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
- data/spec/logstash/util_spec.rb +35 -0
- metadata +364 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/environment"
|
4
|
+
|
5
|
+
describe LogStash::Environment do
|
6
|
+
|
7
|
+
context "when loading jars dependencies" do
|
8
|
+
|
9
|
+
let(:default_jars_location) { File.join("vendor", "jar-dependencies") }
|
10
|
+
let(:default_runtime_location) { File.join(default_jars_location,"runtime-jars","*.jar") }
|
11
|
+
let(:default_test_location) { File.join(default_jars_location,"test-jars","*.jar") }
|
12
|
+
|
13
|
+
it "raises an exception if jruby is not available" do
|
14
|
+
expect(subject).to receive(:jruby?).and_return(false)
|
15
|
+
expect { subject.load_runtime_jars! }.to raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it "find runtime jars in the default location" do
|
19
|
+
expect(subject).to receive(:find_jars).with(default_runtime_location).and_return([])
|
20
|
+
subject.load_runtime_jars!
|
21
|
+
end
|
22
|
+
|
23
|
+
it "find test jars in the default location" do
|
24
|
+
expect(subject).to receive(:find_jars).with(default_test_location).and_return([])
|
25
|
+
subject.load_test_jars!
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when loading a jar file" do
|
29
|
+
|
30
|
+
let(:dummy_jar_file) { File.join(default_jars_location,"runtime-jars","elasticsearch.jar") }
|
31
|
+
|
32
|
+
it "requires the jar files if there are jars to load" do
|
33
|
+
expect(subject).to receive(:find_jars).with(default_runtime_location).and_return([dummy_jar_file])
|
34
|
+
expect(subject).to receive(:require).with(dummy_jar_file)
|
35
|
+
subject.load_runtime_jars!
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an exception if there are no jars to load" do
|
39
|
+
allow(Dir).to receive(:glob).and_return([])
|
40
|
+
expect { subject.load_runtime_jars! }.to raise_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "add_plugin_path" do
|
46
|
+
let(:path) { "/some/path" }
|
47
|
+
|
48
|
+
before(:each) { expect($LOAD_PATH).to_not include(path) }
|
49
|
+
after(:each) { $LOAD_PATH.delete(path) }
|
50
|
+
|
51
|
+
it "should add the path to $LOAD_PATH" do
|
52
|
+
expect{subject.add_plugin_path(path)}.to change{$LOAD_PATH.size}.by(1)
|
53
|
+
expect($LOAD_PATH).to include(path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/json"
|
4
|
+
|
5
|
+
# use a dummy NOOP filter to test Filters::Base
|
6
|
+
class LogStash::Filters::NOOP < LogStash::Filters::Base
|
7
|
+
config_name "noop"
|
8
|
+
milestone 2
|
9
|
+
|
10
|
+
def register; end
|
11
|
+
|
12
|
+
def filter(event)
|
13
|
+
return unless filter?(event)
|
14
|
+
filter_matched(event)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe LogStash::Filters::Base do
|
19
|
+
subject {LogStash::Filters::Base.new({})}
|
20
|
+
|
21
|
+
it "should provide method interfaces to override" do
|
22
|
+
expect{subject.register}.to raise_error(RuntimeError)
|
23
|
+
expect{subject.filter(:foo)}.to raise_error(RuntimeError)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should provide class public API" do
|
27
|
+
[:register, :filter, :multi_filter, :execute, :threadsafe?, :filter_matched, :filter?, :close].each do |method|
|
28
|
+
expect(subject).to respond_to(method)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "multi_filter" do
|
33
|
+
let(:event1){LogStash::Event.new}
|
34
|
+
let(:event2){LogStash::Event.new}
|
35
|
+
|
36
|
+
it "should multi_filter without new events" do
|
37
|
+
allow(subject).to receive(:filter) do |event, &block|
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
expect(subject.multi_filter([event1])).to eq([event1])
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should multi_filter with new events" do
|
44
|
+
allow(subject).to receive(:filter) do |event, &block|
|
45
|
+
block.call(event2)
|
46
|
+
end
|
47
|
+
expect(subject.multi_filter([event1])).to eq([event1, event2])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe LogStash::Filters::NOOP do
|
53
|
+
|
54
|
+
describe "adding multiple values to one field" do
|
55
|
+
config <<-CONFIG
|
56
|
+
filter {
|
57
|
+
noop {
|
58
|
+
add_field => ["new_field", "new_value"]
|
59
|
+
add_field => ["new_field", "new_value_2"]
|
60
|
+
}
|
61
|
+
}
|
62
|
+
CONFIG
|
63
|
+
|
64
|
+
sample "example" do
|
65
|
+
insist { subject["new_field"] } == ["new_value", "new_value_2"]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "type parsing" do
|
70
|
+
config <<-CONFIG
|
71
|
+
filter {
|
72
|
+
noop {
|
73
|
+
add_tag => ["test"]
|
74
|
+
}
|
75
|
+
}
|
76
|
+
CONFIG
|
77
|
+
|
78
|
+
sample("type" => "noop") do
|
79
|
+
insist { subject["tags"] } == ["test"]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "tags parsing with one tag" do
|
84
|
+
config <<-CONFIG
|
85
|
+
filter {
|
86
|
+
noop {
|
87
|
+
add_tag => ["test"]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
CONFIG
|
91
|
+
|
92
|
+
sample("type" => "noop") do
|
93
|
+
insist { subject["tags"] } == ["test"]
|
94
|
+
end
|
95
|
+
|
96
|
+
sample("type" => "noop", "tags" => ["t1", "t2"]) do
|
97
|
+
insist { subject["tags"] } == ["t1", "t2", "test"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "tags parsing with multiple tags" do
|
102
|
+
config <<-CONFIG
|
103
|
+
filter {
|
104
|
+
noop {
|
105
|
+
add_tag => ["test"]
|
106
|
+
}
|
107
|
+
}
|
108
|
+
CONFIG
|
109
|
+
|
110
|
+
sample("type" => "noop") do
|
111
|
+
insist { subject["tags"] } == ["test"]
|
112
|
+
end
|
113
|
+
|
114
|
+
sample("type" => "noop", "tags" => ["t1"]) do
|
115
|
+
insist { subject["tags"] } == ["t1", "test"]
|
116
|
+
end
|
117
|
+
|
118
|
+
sample("type" => "noop", "tags" => ["t1", "t2"]) do
|
119
|
+
insist { subject["tags"] } == ["t1", "t2", "test"]
|
120
|
+
end
|
121
|
+
|
122
|
+
sample("type" => "noop", "tags" => ["t1", "t2", "t3"]) do
|
123
|
+
insist { subject["tags"] } == ["t1", "t2", "t3", "test"]
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "remove_tag" do
|
128
|
+
config <<-CONFIG
|
129
|
+
filter {
|
130
|
+
noop {
|
131
|
+
remove_tag => ["t2", "t3"]
|
132
|
+
}
|
133
|
+
}
|
134
|
+
CONFIG
|
135
|
+
|
136
|
+
sample("type" => "noop", "tags" => ["t4"]) do
|
137
|
+
insist { subject["tags"] } == ["t4"]
|
138
|
+
end
|
139
|
+
|
140
|
+
sample("type" => "noop", "tags" => ["t1", "t2", "t3"]) do
|
141
|
+
insist { subject["tags"] } == ["t1"]
|
142
|
+
end
|
143
|
+
|
144
|
+
# also test from Json deserialized data to test the handling of native Java collections by JrJackson
|
145
|
+
# see https://github.com/elastic/logstash/issues/2261
|
146
|
+
sample(LogStash::Json.load("{\"type\":\"noop\", \"tags\":[\"t1\", \"t2\", \"t3\"]}")) do
|
147
|
+
insist { subject["tags"] } == ["t1"]
|
148
|
+
end
|
149
|
+
|
150
|
+
sample("type" => "noop", "tags" => ["t1", "t2"]) do
|
151
|
+
insist { subject["tags"] } == ["t1"]
|
152
|
+
end
|
153
|
+
|
154
|
+
# also test from Json deserialized data to test the handling of native Java collections by JrJackson
|
155
|
+
# see https://github.com/elastic/logstash/issues/2261
|
156
|
+
sample(LogStash::Json.load("{\"type\":\"noop\", \"tags\":[\"t1\", \"t2\"]}")) do
|
157
|
+
insist { subject["tags"] } == ["t1"]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "remove_tag with dynamic value" do
|
162
|
+
config <<-CONFIG
|
163
|
+
filter {
|
164
|
+
noop {
|
165
|
+
remove_tag => ["%{blackhole}"]
|
166
|
+
}
|
167
|
+
}
|
168
|
+
CONFIG
|
169
|
+
|
170
|
+
sample("type" => "noop", "tags" => ["t1", "goaway", "t3"], "blackhole" => "goaway") do
|
171
|
+
insist { subject["tags"] } == ["t1", "t3"]
|
172
|
+
end
|
173
|
+
|
174
|
+
# also test from Json deserialized data to test the handling of native Java collections by JrJackson
|
175
|
+
# see https://github.com/elastic/logstash/issues/2261
|
176
|
+
sample(LogStash::Json.load("{\"type\":\"noop\", \"tags\":[\"t1\", \"goaway\", \"t3\"], \"blackhole\":\"goaway\"}")) do
|
177
|
+
insist { subject["tags"] } == ["t1", "t3"]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "remove_field" do
|
182
|
+
config <<-CONFIG
|
183
|
+
filter {
|
184
|
+
noop {
|
185
|
+
remove_field => ["t2", "t3"]
|
186
|
+
}
|
187
|
+
}
|
188
|
+
CONFIG
|
189
|
+
|
190
|
+
sample("type" => "noop", "t4" => "four") do
|
191
|
+
insist { subject }.include?("t4")
|
192
|
+
end
|
193
|
+
|
194
|
+
sample("type" => "noop", "t1" => "one", "t2" => "two", "t3" => "three") do
|
195
|
+
insist { subject }.include?("t1")
|
196
|
+
reject { subject }.include?("t2")
|
197
|
+
reject { subject }.include?("t3")
|
198
|
+
end
|
199
|
+
|
200
|
+
sample("type" => "noop", "t1" => "one", "t2" => "two") do
|
201
|
+
insist { subject }.include?("t1")
|
202
|
+
reject { subject }.include?("t2")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "remove_field on deep objects" do
|
207
|
+
config <<-CONFIG
|
208
|
+
filter {
|
209
|
+
noop {
|
210
|
+
remove_field => ["[t1][t2]"]
|
211
|
+
}
|
212
|
+
}
|
213
|
+
CONFIG
|
214
|
+
|
215
|
+
sample("type" => "noop", "t1" => {"t2" => "two", "t3" => "three"}) do
|
216
|
+
insist { subject }.include?("t1")
|
217
|
+
reject { subject }.include?("[t1][t2]")
|
218
|
+
insist { subject }.include?("[t1][t3]")
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "remove_field on array" do
|
223
|
+
config <<-CONFIG
|
224
|
+
filter {
|
225
|
+
noop {
|
226
|
+
remove_field => ["[t1][0]"]
|
227
|
+
}
|
228
|
+
}
|
229
|
+
CONFIG
|
230
|
+
|
231
|
+
sample("type" => "noop", "t1" => ["t2", "t3"]) do
|
232
|
+
insist { subject }.include?("t1")
|
233
|
+
insist { subject["[t1][0]"] } == "t3"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "remove_field with dynamic value in field name" do
|
238
|
+
config <<-CONFIG
|
239
|
+
filter {
|
240
|
+
noop {
|
241
|
+
remove_field => ["%{blackhole}"]
|
242
|
+
}
|
243
|
+
}
|
244
|
+
CONFIG
|
245
|
+
|
246
|
+
sample("type" => "noop", "blackhole" => "go", "go" => "away") do
|
247
|
+
insist { subject }.include?("blackhole")
|
248
|
+
reject { subject }.include?("go")
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
# use a dummy NOOP input to test Inputs::Base
|
5
|
+
class LogStash::Inputs::NOOP < LogStash::Inputs::Base
|
6
|
+
config_name "noop"
|
7
|
+
milestone 2
|
8
|
+
|
9
|
+
def register; end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "LogStash::Inputs::Base#decorate" do
|
14
|
+
it "should add tag" do
|
15
|
+
input = LogStash::Inputs::NOOP.new("tags" => "value")
|
16
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
17
|
+
input.instance_eval {decorate(evt)}
|
18
|
+
expect(evt["tags"]).to eq(["value"])
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should add multiple tag" do
|
22
|
+
input = LogStash::Inputs::NOOP.new("tags" => ["value1","value2"])
|
23
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
24
|
+
input.instance_eval {decorate(evt)}
|
25
|
+
expect(evt["tags"]).to eq(["value1","value2"])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should allow duplicates tag" do
|
29
|
+
input = LogStash::Inputs::NOOP.new("tags" => ["value","value"])
|
30
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
31
|
+
input.instance_eval {decorate(evt)}
|
32
|
+
expect(evt["tags"]).to eq(["value","value"])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should add tag with sprintf" do
|
36
|
+
input = LogStash::Inputs::NOOP.new("tags" => "%{type}")
|
37
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
38
|
+
input.instance_eval {decorate(evt)}
|
39
|
+
expect(evt["tags"]).to eq(["noop"])
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should add single field" do
|
43
|
+
input = LogStash::Inputs::NOOP.new("add_field" => {"field" => "value"})
|
44
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
45
|
+
input.instance_eval {decorate(evt)}
|
46
|
+
expect(evt["field"]).to eq("value")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should add single field with sprintf" do
|
50
|
+
input = LogStash::Inputs::NOOP.new("add_field" => {"%{type}" => "%{type}"})
|
51
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
52
|
+
input.instance_eval {decorate(evt)}
|
53
|
+
expect(evt["noop"]).to eq("noop")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should add multiple field" do
|
57
|
+
input = LogStash::Inputs::NOOP.new("add_field" => {"field" => ["value1", "value2"], "field2" => "value"})
|
58
|
+
evt = LogStash::Event.new({"type" => "noop"})
|
59
|
+
input.instance_eval {decorate(evt)}
|
60
|
+
expect(evt["field"]).to eq(["value1","value2"])
|
61
|
+
expect(evt["field2"]).to eq("value")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "LogStash::Inputs::Base#fix_streaming_codecs" do
|
66
|
+
it "should carry the charset setting along when switching" do
|
67
|
+
require "logstash/inputs/tcp"
|
68
|
+
require "logstash/codecs/plain"
|
69
|
+
plain = LogStash::Codecs::Plain.new("charset" => "CP1252")
|
70
|
+
tcp = LogStash::Inputs::Tcp.new("codec" => plain, "port" => 3333)
|
71
|
+
tcp.instance_eval { fix_streaming_codecs }
|
72
|
+
expect(tcp.codec.charset).to eq("CP1252")
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
require "logstash/java_integration"
|
4
|
+
|
5
|
+
describe "Java integration" do
|
6
|
+
|
7
|
+
context "type equivalence" do
|
8
|
+
|
9
|
+
# here we test for both is_a? and case/when usage of the Java types
|
10
|
+
# because these are the specific use-cases in our code and the expected
|
11
|
+
# behaviour.
|
12
|
+
|
13
|
+
context "Java::JavaUtil::ArrayList" do
|
14
|
+
|
15
|
+
it "should report to be a Ruby Array" do
|
16
|
+
expect(Java::JavaUtil::ArrayList.new.is_a?(Array)).to eq(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be class equivalent to Ruby Array" do
|
20
|
+
expect do
|
21
|
+
case Java::JavaUtil::ArrayList.new
|
22
|
+
when Array
|
23
|
+
true
|
24
|
+
else
|
25
|
+
raise
|
26
|
+
end
|
27
|
+
end.not_to raise_error
|
28
|
+
|
29
|
+
expect(Array === Java::JavaUtil::ArrayList.new).to eq(true)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "Java::JavaUtil::LinkedHashMap" do
|
34
|
+
it "should report to be a Ruby Hash" do
|
35
|
+
expect(Java::JavaUtil::LinkedHashMap.new.is_a?(Hash)).to eq(true)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be class equivalent to Ruby Hash" do
|
39
|
+
expect do
|
40
|
+
case Java::JavaUtil::LinkedHashMap.new
|
41
|
+
when Hash
|
42
|
+
true
|
43
|
+
else
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
end.not_to raise_error
|
47
|
+
|
48
|
+
expect(Hash === Java::JavaUtil::LinkedHashMap.new).to eq(true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "Java::JavaUtil::Map" do
|
54
|
+
# this is to test the Java 8 Map interface change for the merge method
|
55
|
+
|
56
|
+
let(:merger){{:a => 1, :b => 2}}
|
57
|
+
let(:mergee){{:b => 3, :c => 4}}
|
58
|
+
|
59
|
+
shared_examples "map merge" do
|
60
|
+
it "should support merging" do
|
61
|
+
expect(subject.merge(mergee)).to eq({:a => 1, :b => 3, :c => 4})
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return a new hash and not change original hash" do
|
65
|
+
expect{subject.merge(mergee)}.to_not change{subject}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with Java::JavaUtil::LinkedHashMap" do
|
70
|
+
it_behaves_like "map merge" do
|
71
|
+
subject{Java::JavaUtil::LinkedHashMap.new(merger)}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with Java::JavaUtil::HashMap" do
|
76
|
+
it_behaves_like "map merge" do
|
77
|
+
subject{Java::JavaUtil::HashMap.new(merger)}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "Java::JavaUtil::Collection" do
|
83
|
+
subject{Java::JavaUtil::ArrayList.new(initial_array)}
|
84
|
+
|
85
|
+
context "when inspecting" do
|
86
|
+
let(:items) { [:a, {:b => :c}] }
|
87
|
+
subject { java.util.ArrayList.new(items) }
|
88
|
+
|
89
|
+
it "should include the contents of the Collection" do
|
90
|
+
expect(subject.inspect).to include(items.inspect)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should include the class name" do
|
94
|
+
expect(subject.inspect).to include("ArrayList")
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should include the hash code of the collection" do
|
98
|
+
expect(subject.inspect).to include(subject.hashCode.to_s)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when deleting a unique instance" do
|
103
|
+
let(:initial_array) {["foo", "bar"]}
|
104
|
+
|
105
|
+
it "should return the deleted object" do
|
106
|
+
expect(subject.delete("foo")).to eq("foo")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should remove the object to delete" do
|
110
|
+
expect{subject.delete("foo")}.to change{subject.to_a}.from(initial_array).to(["bar"])
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when deleting multiple instances" do
|
115
|
+
let(:initial_array) {["foo", "bar", "foo"]}
|
116
|
+
|
117
|
+
it "should return the last deleted object" do
|
118
|
+
expect(subject.delete("foo")).to eq("foo")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should remove all the objects to delete" do
|
122
|
+
expect{subject.delete("foo")}.to change{subject.to_a}.from(initial_array).to(["bar"])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when deleting non existing object" do
|
127
|
+
let(:initial_array) {["foo", "bar", "foo"]}
|
128
|
+
|
129
|
+
it "should return nil" do
|
130
|
+
expect(subject.delete("baz")).to be_nil
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should not change the collection" do
|
134
|
+
expect{subject.delete("baz")}.to_not change{subject.to_a}
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should yield to block when given" do
|
138
|
+
expect(subject.delete("baz"){"foobar"}).to eq("foobar")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when deleting on empty collection" do
|
143
|
+
let(:initial_array) {[]}
|
144
|
+
|
145
|
+
it "should return nil" do
|
146
|
+
expect(subject.delete("baz")).to be_nil
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not change the collection" do
|
150
|
+
expect{subject.delete("baz")}.to_not change{subject.to_a}
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "when intersecting with a Ruby Array" do
|
155
|
+
|
156
|
+
context "using string collection with duplicates and single result" do
|
157
|
+
let(:initial_array) {["foo", "bar", "foo"]}
|
158
|
+
|
159
|
+
it "should not change original collection" do
|
160
|
+
expect{subject & ["foo"]}.to_not change{subject.to_a}
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should return a new array containing elements common to the two arrays, excluding any duplicate" do
|
164
|
+
expect((subject & ["foo"]).to_a).to eq(["foo"])
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "using string collection with duplicates and multiple results" do
|
169
|
+
let(:original) {["foo", "bar", "foo", "baz"]}
|
170
|
+
let(:target) {["baz", "foo"]}
|
171
|
+
let(:result) {["foo", "baz"]}
|
172
|
+
|
173
|
+
it "should return a new array containing elements common to the two arrays, excluding any duplicate and preserve order from the original array" do
|
174
|
+
# this is the Ruby contract
|
175
|
+
expect(original & target).to eq(result)
|
176
|
+
|
177
|
+
# this should work the same
|
178
|
+
expect((Java::JavaUtil::ArrayList.new(original) & target).to_a).to eq(result)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "Ruby doc examples" do
|
183
|
+
it "should return a new array containing elements common to the two arrays, excluding any duplicate" do
|
184
|
+
expect(Java::JavaUtil::ArrayList.new(([1, 1, 3, 5]) & [1, 2, 3]).to_a).to eq([1, 3])
|
185
|
+
expect(Java::JavaUtil::ArrayList.new((['a', 'b', 'b', 'z']) & ['a', 'b', 'c']).to_a).to eq(['a', 'b'])
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context "when unioning with a Ruby Array" do
|
191
|
+
|
192
|
+
context "using string collection with duplicates" do
|
193
|
+
let(:initial_array) {["foo", "bar", "foo"]}
|
194
|
+
|
195
|
+
it "should not change original collection" do
|
196
|
+
expect{subject | ["bar", "baz"]}.to_not change{subject.to_a}
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should return a new array by joining excluding any duplicates and preserving the order from the original array" do
|
200
|
+
expect((subject | ["bar", "baz"]).to_a).to eq(["foo", "bar", "baz"])
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should remove duplicates when joining empty array" do
|
204
|
+
expect((subject | []).to_a).to eq(["foo", "bar"])
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context "Ruby doc examples" do
|
209
|
+
it "should return a new array containing elements common to the two arrays, excluding any duplicate" do
|
210
|
+
expect(Java::JavaUtil::ArrayList.new((["a", "b", "c"]) | ["c", "d", "a"]).to_a).to eq(["a", "b", "c", "d"])
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "when compacting" do
|
216
|
+
context "#compact with nils" do
|
217
|
+
let(:initial_array) { [1,2,3,nil,nil,6] }
|
218
|
+
it "should remove nil values from a copy" do
|
219
|
+
expect(subject.compact).to eq([1,2,3,6])
|
220
|
+
expect(subject).to eq([1,2,3,nil,nil,6])
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "#compact! with nils" do
|
225
|
+
let(:initial_array) { [1,2,3,nil,nil,6] }
|
226
|
+
it "should remove nil values" do
|
227
|
+
expect(subject.compact!).to eq([1,2,3,6])
|
228
|
+
expect(subject).to eq([1,2,3,6])
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should return the original" do
|
232
|
+
expect(subject.compact!.object_id).to eq(subject.object_id)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "#compact! without nils" do
|
237
|
+
let(:initial_array) { [1,2,3,6] }
|
238
|
+
it "should return nil" do
|
239
|
+
expect(subject.compact!).to be nil
|
240
|
+
expect(subject).to eq([1,2,3,6])
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "Enumerable implementation" do
|
247
|
+
context "Java Map interface should report key with nil value as included" do
|
248
|
+
|
249
|
+
it "should support include? method" do
|
250
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => nil}).include?("foo")).to eq(true)
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should support has_key? method" do
|
254
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => nil}).has_key?("foo")).to eq(true)
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should support member? method" do
|
258
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => nil}).member?("foo")).to eq(true)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should support key? method" do
|
262
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => nil}).key?("foo")).to eq(true)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context "Java Map interface should report key with a value as included" do
|
267
|
+
|
268
|
+
it "should support include? method" do
|
269
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).include?("foo")).to eq(true)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should support has_key? method" do
|
273
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).has_key?("foo")).to eq(true)
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should support member? method" do
|
277
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).member?("foo")).to eq(true)
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should support key? method" do
|
281
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).key?("foo")).to eq(true)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context "Java Map interface should report non existing key as not included" do
|
286
|
+
|
287
|
+
it "should support include? method" do
|
288
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1})).not_to include("bar")
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should support has_key? method" do
|
292
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).has_key?("bar")).to eq(false)
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should support member? method" do
|
296
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).member?("bar")).to eq(false)
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should support key? method" do
|
300
|
+
expect(Java::JavaUtil::LinkedHashMap.new({"foo" => 1}).key?("bar")).to eq(false)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|