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.

Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/lib/logstash-core.rb +1 -0
  3. data/lib/logstash-core/logstash-core.rb +3 -0
  4. data/lib/logstash-core/version.rb +8 -0
  5. data/lib/logstash/agent.rb +391 -0
  6. data/lib/logstash/codecs/base.rb +50 -0
  7. data/lib/logstash/config/config_ast.rb +550 -0
  8. data/lib/logstash/config/cpu_core_strategy.rb +32 -0
  9. data/lib/logstash/config/defaults.rb +12 -0
  10. data/lib/logstash/config/file.rb +39 -0
  11. data/lib/logstash/config/grammar.rb +3503 -0
  12. data/lib/logstash/config/mixin.rb +518 -0
  13. data/lib/logstash/config/registry.rb +13 -0
  14. data/lib/logstash/environment.rb +98 -0
  15. data/lib/logstash/errors.rb +12 -0
  16. data/lib/logstash/filters/base.rb +205 -0
  17. data/lib/logstash/inputs/base.rb +116 -0
  18. data/lib/logstash/inputs/threadable.rb +18 -0
  19. data/lib/logstash/java_integration.rb +116 -0
  20. data/lib/logstash/json.rb +61 -0
  21. data/lib/logstash/logging.rb +91 -0
  22. data/lib/logstash/namespace.rb +13 -0
  23. data/lib/logstash/output_delegator.rb +172 -0
  24. data/lib/logstash/outputs/base.rb +91 -0
  25. data/lib/logstash/patches.rb +5 -0
  26. data/lib/logstash/patches/bugfix_jruby_2558.rb +51 -0
  27. data/lib/logstash/patches/cabin.rb +35 -0
  28. data/lib/logstash/patches/profile_require_calls.rb +47 -0
  29. data/lib/logstash/patches/rubygems.rb +38 -0
  30. data/lib/logstash/patches/stronger_openssl_defaults.rb +68 -0
  31. data/lib/logstash/pipeline.rb +499 -0
  32. data/lib/logstash/pipeline_reporter.rb +114 -0
  33. data/lib/logstash/plugin.rb +120 -0
  34. data/lib/logstash/program.rb +14 -0
  35. data/lib/logstash/runner.rb +124 -0
  36. data/lib/logstash/shutdown_watcher.rb +100 -0
  37. data/lib/logstash/util.rb +203 -0
  38. data/lib/logstash/util/buftok.rb +139 -0
  39. data/lib/logstash/util/charset.rb +35 -0
  40. data/lib/logstash/util/decorators.rb +52 -0
  41. data/lib/logstash/util/defaults_printer.rb +31 -0
  42. data/lib/logstash/util/filetools.rb +186 -0
  43. data/lib/logstash/util/java_version.rb +66 -0
  44. data/lib/logstash/util/password.rb +25 -0
  45. data/lib/logstash/util/plugin_version.rb +56 -0
  46. data/lib/logstash/util/prctl.rb +10 -0
  47. data/lib/logstash/util/retryable.rb +40 -0
  48. data/lib/logstash/util/socket_peer.rb +7 -0
  49. data/lib/logstash/util/unicode_trimmer.rb +81 -0
  50. data/lib/logstash/util/worker_threads_default_printer.rb +29 -0
  51. data/lib/logstash/util/wrapped_synchronous_queue.rb +41 -0
  52. data/lib/logstash/version.rb +14 -0
  53. data/locales/en.yml +204 -0
  54. data/logstash-core.gemspec +58 -0
  55. data/spec/conditionals_spec.rb +429 -0
  56. data/spec/logstash/agent_spec.rb +85 -0
  57. data/spec/logstash/config/config_ast_spec.rb +146 -0
  58. data/spec/logstash/config/cpu_core_strategy_spec.rb +123 -0
  59. data/spec/logstash/config/defaults_spec.rb +10 -0
  60. data/spec/logstash/config/mixin_spec.rb +158 -0
  61. data/spec/logstash/environment_spec.rb +56 -0
  62. data/spec/logstash/filters/base_spec.rb +251 -0
  63. data/spec/logstash/inputs/base_spec.rb +74 -0
  64. data/spec/logstash/java_integration_spec.rb +304 -0
  65. data/spec/logstash/json_spec.rb +96 -0
  66. data/spec/logstash/output_delegator_spec.rb +144 -0
  67. data/spec/logstash/outputs/base_spec.rb +40 -0
  68. data/spec/logstash/patches_spec.rb +90 -0
  69. data/spec/logstash/pipeline_reporter_spec.rb +85 -0
  70. data/spec/logstash/pipeline_spec.rb +455 -0
  71. data/spec/logstash/plugin_spec.rb +169 -0
  72. data/spec/logstash/runner_spec.rb +68 -0
  73. data/spec/logstash/shutdown_watcher_spec.rb +113 -0
  74. data/spec/logstash/util/buftok_spec.rb +31 -0
  75. data/spec/logstash/util/charset_spec.rb +74 -0
  76. data/spec/logstash/util/defaults_printer_spec.rb +50 -0
  77. data/spec/logstash/util/java_version_spec.rb +79 -0
  78. data/spec/logstash/util/plugin_version_spec.rb +64 -0
  79. data/spec/logstash/util/unicode_trimmer_spec.rb +55 -0
  80. data/spec/logstash/util/worker_threads_default_printer_spec.rb +45 -0
  81. data/spec/logstash/util/wrapped_synchronous_queue_spec.rb +28 -0
  82. data/spec/logstash/util_spec.rb +35 -0
  83. 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