logstash-filter-mutate 3.5.8 → 3.5.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a35944145cf520f4dc7a0249e8d4c75e60abcf0c454545f0fb9a4a70af223bea
4
- data.tar.gz: 431b8427123636a98fa9c51a4460157d6018cd594c927e95e9028048f49c2e3a
3
+ metadata.gz: 9fd4fb3b414af0266ba7a62e6ef72b00ad1b109200d8da6b54ee7910a1ba561b
4
+ data.tar.gz: 6368b980d3d5c1b32f139bfc007341cafff738a2db055df8c3534436c836b729
5
5
  SHA512:
6
- metadata.gz: 1c7c36f559f8733d38ba8d87f2017418b380c1178100fb4a7641cb5c80e5440b06e5e6aaed46b3f9c53be3a5aeaa245bb3f2fd90a90a41ddd105c3ff00046ffb
7
- data.tar.gz: b8b4c405276c6714db052d3cd1a46a5286c4ef787dd9aad33b7861468e6d83410f13eea597dc41aee0a03d6e110a40ace196bb687efba0caa417114bfdeb6bb3
6
+ metadata.gz: 6ba63632430477006fc77d5d27e3ee14c72f4e1bc5bd9557ba886c31b95b34636fd1ed7869dfc77c3a95d02355b04f0afa1e4a4c6053b715d8769c7c5fc1895b
7
+ data.tar.gz: b971f7880a0a98ee89545b5775fcde5c67adb48b624c5b6885b6a70476352950c246d1577d9e133b82b1979b89f7f1500b156a27ed5f6ca3a4fa016e327767e0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 3.5.9
2
+ - Fix `convert` to covert hexadecimal float notation and scientific notation string to float and integer [#175](https://github.com/logstash-plugins/logstash-filter-mutate/pull/175)
3
+
1
4
  ## 3.5.8
2
5
  - Fix "Can't modify frozen string" error when converting boolean to `string` [#171](https://github.com/logstash-plugins/logstash-filter-mutate/pull/171)
3
6
 
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/filters/base"
3
3
  require "logstash/namespace"
4
+ require "bigdecimal"
4
5
 
5
6
  # The mutate filter allows you to perform general mutations on fields. You
6
7
  # can rename, replace, and modify fields in your events.
@@ -227,6 +228,10 @@ class LogStash::Filters::Mutate < LogStash::Filters::Base
227
228
  )
228
229
  end
229
230
  end
231
+ # fallback to old type conversion behavior prior to Logstash 8.14.0
232
+ @lenient_conversion = self.class.is_lenient_version?
233
+ # signed hex parsing support in jruby 10
234
+ @support_signed_hex = self.class.can_parse_signed_hex?
230
235
 
231
236
  @gsub_parsed = []
232
237
  @gsub.nil? or @gsub.each_slice(3) do |field, needle, replacement|
@@ -342,17 +347,44 @@ class LogStash::Filters::Mutate < LogStash::Filters::Base
342
347
  end
343
348
 
344
349
  def convert_integer(value)
350
+ value = value.strip.delete(',').downcase if value.is_a?(String)
351
+
345
352
  return 1 if value == true
346
353
  return 0 if value == false
347
- return value.to_i if !value.is_a?(String)
348
- value.tr(",", "").to_i
354
+ return value if value.is_a?(Integer)
355
+ return value.to_i if @lenient_conversion
356
+
357
+ if value.is_a?(String)
358
+ signed_float = parse_signed_hex_str(value)
359
+ # hex number
360
+ if signed_float
361
+ return Integer(value) if value.count(".").zero?
362
+ return Integer(signed_float)
363
+ end
364
+
365
+ # scientific notation. BigDecimal() can't parse hex string
366
+ return BigDecimal(value).to_i if value.include?("e")
367
+ # maybe a float string
368
+ return value.to_i
369
+ end
370
+
371
+ Integer(value)
349
372
  end
350
373
 
351
374
  def convert_float(value)
375
+ value = value.strip.delete(',').downcase if value.is_a?(String)
376
+
352
377
  return 1.0 if value == true
353
378
  return 0.0 if value == false
354
- value = value.delete(",") if value.kind_of?(String)
355
- value.to_f
379
+ return value if value.is_a?(Float)
380
+ return value.to_f if @lenient_conversion
381
+
382
+ if value.is_a?(String)
383
+ signed_float = parse_signed_hex_str(value)
384
+ return signed_float if signed_float
385
+ end
386
+
387
+ Float(value)
356
388
  end
357
389
 
358
390
  def convert_integer_eu(value)
@@ -374,6 +406,25 @@ class LogStash::Filters::Mutate < LogStash::Filters::Base
374
406
  value.tr(",.", ".,")
375
407
  end
376
408
 
409
+ # Parses a string to determine if it represents a signed hexadecimal number.
410
+ # If the string matches a signed hex format (eg "-0x1A"), returns the signed float value.
411
+ # JRuby Float() can parse signed hex string and uppercase hex string in version 10+,
412
+ # but not in earlier versions.
413
+ #
414
+ # @param value [String] the string to parse
415
+ # @return [Float, nil] the signed float value if hex, or nil if not a hex string
416
+ def parse_signed_hex_str(value)
417
+ return Float(value) if @support_signed_hex
418
+
419
+ if value.match?(/^[+-]?0x/i)
420
+ sign = value.start_with?('-') ? -1 : 1
421
+ unsigned = value.sub(/^[+-]/, '')
422
+ return sign * Float(unsigned)
423
+ end
424
+
425
+ nil
426
+ end
427
+
377
428
  def gsub(event)
378
429
  @gsub_parsed.each do |config|
379
430
  field = config[:field]
@@ -542,4 +593,14 @@ class LogStash::Filters::Mutate < LogStash::Filters::Base
542
593
  event.set(dest_field,LogStash::Util.deep_clone(original))
543
594
  end
544
595
  end
596
+
597
+ def self.is_lenient_version?
598
+ Gem::Version.new(LOGSTASH_VERSION) < Gem::Version.new("8.14.0")
599
+ end
600
+
601
+ def self.can_parse_signed_hex?
602
+ Float("-0x1A") == -26.0
603
+ rescue ArgumentError
604
+ false
605
+ end
545
606
  end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-filter-mutate'
4
- s.version = '3.5.8'
4
+ s.version = '3.5.9'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Performs mutations on fields"
7
7
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -318,7 +318,7 @@ describe LogStash::Filters::Mutate do
318
318
  convert => [ "message", "int"] #should be integer
319
319
  }
320
320
  }
321
- CONFIG
321
+ CONFIG
322
322
 
323
323
  sample "not_really_important" do
324
324
  expect {subject}.to raise_error(LogStash::ConfigurationError, /Invalid conversion type/)
@@ -1122,4 +1122,451 @@ describe LogStash::Filters::Mutate do
1122
1122
  end
1123
1123
  end
1124
1124
 
1125
+ describe "convert makes type conversions" do
1126
+ context "to string" do
1127
+ config <<-CONFIG
1128
+ filter {
1129
+ mutate { convert => { "a" => "string" } }
1130
+ }
1131
+ CONFIG
1132
+
1133
+ context "123" do
1134
+ # Integer
1135
+ sample({ "a" => 123 }) do
1136
+ expect(subject.get("a")).to be_a(String).and eq("123")
1137
+ end
1138
+ # Float
1139
+ sample({ "a" => Float(123.0) }) do
1140
+ expect(subject.get("a")).to be_a(String).and eq("123.0")
1141
+ end
1142
+ # String
1143
+ sample({ "a" => "123" }) do
1144
+ expect(subject.get("a")).to be_a(String).and eq("123")
1145
+ end
1146
+ sample({ "a" => "0x7b" }) do
1147
+ expect(subject.get("a")).to be_a(String).and eq("0x7b")
1148
+ end
1149
+ sample({ "a" => "123.0" }) do
1150
+ expect(subject.get("a")).to be_a(String).and eq("123.0")
1151
+ end
1152
+ sample({ "a" => "1.230000e+02" }) do
1153
+ expect(subject.get("a")).to be_a(String).and eq("1.230000e+02")
1154
+ end
1155
+ end
1156
+
1157
+ context "123.45" do
1158
+ # Float
1159
+ sample({ "a" => Float(123.45) }) do
1160
+ expect(subject.get("a")).to be_a(String).and eq("123.45")
1161
+ end
1162
+ # String
1163
+ sample({ "a" => "123.45" }) do
1164
+ expect(subject.get("a")).to be_a(String).and eq("123.45")
1165
+ end
1166
+ sample({ "a" => "1.234500e+02" }) do
1167
+ expect(subject.get("a")).to be_a(String).and eq("1.234500e+02")
1168
+ end
1169
+ sample({ "a" => "0x1.edcdp6" }) do
1170
+ expect(subject.get("a")).to be_a(String).and eq( "0x1.edcdp6" )
1171
+ end
1172
+ end
1173
+
1174
+ context "16777217" do
1175
+ # Integer
1176
+ sample({ "a" => 16777217 }) do
1177
+ expect(subject.get("a")).to be_a(String).and eq("16777217")
1178
+ end
1179
+ # Float
1180
+ sample({ "a" => 1.6777217E7 }) do
1181
+ expect(subject.get("a")).to be_a(String).and eq("16777217.0")
1182
+ end
1183
+ # String
1184
+ sample({ "a" => "16777217" }) do
1185
+ expect(subject.get("a")).to be_a(String).and eq("16777217")
1186
+ end
1187
+ sample({ "a" => "16777217.0" }) do
1188
+ expect(subject.get("a")).to be_a(String).and eq("16777217.0")
1189
+ end
1190
+ end
1191
+
1192
+ context "2147483648" do
1193
+ # Long
1194
+ sample({ "a" => 2147483648 }) do
1195
+ expect(subject.get("a")).to be_a(String).and eq("2147483648")
1196
+ end
1197
+ # Double
1198
+ sample({ "a" => 2.147483648E9 }) do
1199
+ expect(subject.get("a")).to be_a(String).and eq("2147483648.0")
1200
+ end
1201
+ # String
1202
+ sample({ "a" => "2147483648" }) do
1203
+ expect(subject.get("a")).to be_a(String).and eq("2147483648")
1204
+ end
1205
+ sample({ "a" => "2147483648.0" }) do
1206
+ expect(subject.get("a")).to be_a(String).and eq("2147483648.0")
1207
+ end
1208
+ end
1209
+
1210
+ context "9007199254740993" do
1211
+ # Long
1212
+ sample({ "a" => 9007199254740993 }) do
1213
+ expect(subject.get("a")).to be_a(String).and eq("9007199254740993")
1214
+ end
1215
+ # String
1216
+ sample({ "a" => "9007199254740993" }) do
1217
+ expect(subject.get("a")).to be_a(String).and eq("9007199254740993")
1218
+ end
1219
+ sample({ "a" => "9007199254740993.0" }) do
1220
+ expect(subject.get("a")).to be_a(String).and eq("9007199254740993.0")
1221
+ end
1222
+ end
1223
+
1224
+
1225
+ context "9223372036854775808" do
1226
+ # String
1227
+ sample({ "a" => "9223372036854775808" }) do
1228
+ expect(subject.get("a")).to be_a(String).and eq("9223372036854775808")
1229
+ end
1230
+ sample({ "a" => "9223372036854775808.0" }) do
1231
+ expect(subject.get("a")).to be_a(String).and eq("9223372036854775808.0")
1232
+ end
1233
+ end
1234
+
1235
+ context "680564693277057720000000000000000000000" do
1236
+ # String
1237
+ sample({ "a" => "680564693277057720000000000000000000000" }) do
1238
+ expect(subject.get("a")).to be_a(String).and eq("680564693277057720000000000000000000000")
1239
+ end
1240
+ sample({ "a" => "680564693277057720000000000000000000000.0" }) do
1241
+ expect(subject.get("a")).to be_a(String).and eq("680564693277057720000000000000000000000.0")
1242
+ end
1243
+ end
1244
+ end
1245
+
1246
+ context "to integer" do
1247
+ config <<-CONFIG
1248
+ filter {
1249
+ mutate { convert => { "a" => "integer" } }
1250
+ }
1251
+ CONFIG
1252
+
1253
+ context "123" do
1254
+ # Integer
1255
+ sample({ "a" => 123 }) do
1256
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1257
+ end
1258
+ # Float
1259
+ sample({ "a" => Float(123.0) }) do
1260
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1261
+ end
1262
+ # String
1263
+ sample({ "a" => "123" }) do
1264
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1265
+ end
1266
+ sample({ "a" => "0x7b" }) do
1267
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1268
+ end
1269
+ sample({ "a" => "123.0" }) do
1270
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1271
+ end
1272
+ sample({ "a" => "1.230000e+02" }) do
1273
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1274
+ end
1275
+ end
1276
+
1277
+ context "123.45" do
1278
+ # Float
1279
+ sample({ "a" => Float(123.45) }) do
1280
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1281
+ end
1282
+ # String
1283
+ sample({ "a" => "123.45" }) do
1284
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1285
+ end
1286
+ sample({ "a" => "1.234500e+02" }) do
1287
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1288
+ end
1289
+ sample({ "a" => "0x1.edcdp6" }) do
1290
+ expect(subject.get("a")).to be_a(Integer).and eq(123)
1291
+ end
1292
+ end
1293
+
1294
+ context "-123.45" do
1295
+ # Float
1296
+ sample({ "a" => Float(-123.45) }) do
1297
+ expect(subject.get("a")).to be_a(Integer).and eq(-123)
1298
+ end
1299
+ # String
1300
+ sample({ "a" => "-123.45" }) do
1301
+ expect(subject.get("a")).to be_a(Integer).and eq(-123)
1302
+ end
1303
+ sample({ "a" => "-1.234500e+02" }) do
1304
+ expect(subject.get("a")).to be_a(Integer).and eq(-123)
1305
+ end
1306
+ sample({ "a" => "-0x1.edcdp6" }) do
1307
+ expect(subject.get("a")).to be_a(Integer).and eq(-123)
1308
+ end
1309
+ end
1310
+
1311
+ context "16777217" do
1312
+ # Integer
1313
+ sample({ "a" => 16777217 }) do
1314
+ expect(subject.get("a")).to be_a(Integer).and eq(16777217)
1315
+ end
1316
+ # Double
1317
+ sample({ "a" => 1.6777217E7 }) do
1318
+ expect(subject.get("a")).to be_a(Integer).and eq(16777217)
1319
+ end
1320
+ # String
1321
+ sample({ "a" => "16777217" }) do
1322
+ expect(subject.get("a")).to be_a(Integer).and eq(16777217)
1323
+ end
1324
+ sample({ "a" => "16777217.0" }) do
1325
+ expect(subject.get("a")).to be_a(Integer).and eq(16777217)
1326
+ end
1327
+ end
1328
+
1329
+ context "2147483648" do
1330
+ # Long
1331
+ sample({ "a" => 2147483648 }) do
1332
+ expect(subject.get("a")).to be_a(Integer).and eq(2147483648)
1333
+ end
1334
+ # Double
1335
+ sample({ "a" => 2.147483648E9 }) do
1336
+ expect(subject.get("a")).to be_a(Integer).and eq(2147483648)
1337
+ end
1338
+ # String
1339
+ sample({ "a" => "2147483648" }) do
1340
+ expect(subject.get("a")).to be_a(Integer).and eq(2147483648)
1341
+ end
1342
+ sample({ "a" => "2147483648.0" }) do
1343
+ expect(subject.get("a")).to be_a(Integer).and eq(2147483648)
1344
+ end
1345
+ end
1346
+
1347
+ context "9007199254740993" do
1348
+ # Long
1349
+ sample({ "a" => 9007199254740993 }) do
1350
+ expect(subject.get("a")).to be_a(Integer).and eq(9007199254740993)
1351
+ end
1352
+ # String
1353
+ sample({ "a" => "9007199254740993" }) do
1354
+ expect(subject.get("a")).to be_a(Integer).and eq(9007199254740993)
1355
+ end
1356
+ sample({ "a" => "9007199254740993.0" }) do
1357
+ expect(subject.get("a")).to be_a(Integer).and eq(9007199254740993)
1358
+ end
1359
+ sample({ "a" => "9.007199254740993e+15" }) do
1360
+ expect(subject.get("a")).to be_a(Integer).and eq(9007199254740993)
1361
+ end
1362
+ end
1363
+
1364
+ context "9223372036854775808" do
1365
+ # String
1366
+ sample({ "a" => "9223372036854775808" }) do
1367
+ expect(subject.get("a")).to be_a(Integer).and eq(9223372036854775808)
1368
+ end
1369
+ sample({ "a" => "9223372036854775808.0" }) do
1370
+ expect(subject.get("a")).to be_a(Integer).and eq(9223372036854775808)
1371
+ end
1372
+ end
1373
+
1374
+ context "680564693277057720000000000000000000000" do
1375
+ # String
1376
+ sample({ "a" => "680564693277057720000000000000000000000" }) do
1377
+ expect(subject.get("a")).to be_a(Integer).and eq(680564693277057720000000000000000000000)
1378
+ end
1379
+ sample({ "a" => "680564693277057720000000000000000000000.0" }) do
1380
+ expect(subject.get("a")).to be_a(Integer).and eq(680564693277057720000000000000000000000)
1381
+ end
1382
+ end
1383
+
1384
+ end
1385
+
1386
+ context "to float" do
1387
+ config <<-CONFIG
1388
+ filter {
1389
+ mutate { convert => { "a" => "float" } }
1390
+ }
1391
+ CONFIG
1392
+
1393
+ context "123" do
1394
+ # Integer
1395
+ sample({ "a" => 123 }) do
1396
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1397
+ end
1398
+ # Float
1399
+ sample({ "a" => Float(123) }) do
1400
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1401
+ end
1402
+ # String
1403
+ sample({ "a" => "123" }) do
1404
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1405
+ end
1406
+ sample({ "a" => "0x7b" }) do
1407
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1408
+ end
1409
+ sample({ "a" => "123.0" }) do
1410
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1411
+ end
1412
+ sample({ "a" => "1.230000e+02" }) do
1413
+ expect(subject.get("a")).to be_a(Float).and eq(123.0)
1414
+ end
1415
+ end
1416
+
1417
+ context "123.45" do
1418
+ # Float
1419
+ sample({ "a" => Float(123.45) }) do
1420
+ expect(subject.get("a")).to be_a(Float).and eq(123.45)
1421
+ end
1422
+ # String
1423
+ sample({ "a" => "123.45" }) do
1424
+ expect(subject.get("a")).to be_a(Float).and eq(123.45)
1425
+ end
1426
+ sample({ "a" => "1.234500e+02" }) do
1427
+ expect(subject.get("a")).to be_a(Float).and eq(123.45)
1428
+ end
1429
+ sample({ "a" => "0x1.edcdp6" }) do
1430
+ expect(subject.get("a")).to be_a(Float).and eq(123.4501953125)
1431
+ end
1432
+ end
1433
+
1434
+ context "-123.45" do
1435
+ # Float
1436
+ sample({ "a" => Float(-123.45) }) do
1437
+ expect(subject.get("a")).to be_a(Float).and eq(-123.45)
1438
+ end
1439
+ # String
1440
+ sample({ "a" => "-123.45" }) do
1441
+ expect(subject.get("a")).to be_a(Float).and eq(-123.45)
1442
+ end
1443
+ sample({ "a" => "-1.234500e+02" }) do
1444
+ expect(subject.get("a")).to be_a(Float).and eq(-123.45)
1445
+ end
1446
+ sample({ "a" => "-0x1.edcdp6" }) do
1447
+ expect(subject.get("a")).to be_a(Float).and eq(-123.4501953125)
1448
+ end
1449
+ end
1450
+
1451
+ context "16777217" do
1452
+ # Integer
1453
+ sample({ "a" => 16777217 }) do
1454
+ expect(subject.get("a")).to be_a(Float).and eq(1.6777217E7)
1455
+ end
1456
+ # Float
1457
+ sample({ "a" => 1.6777217E7 }) do
1458
+ expect(subject.get("a")).to be_a(Float).and eq(1.6777217E7)
1459
+ end
1460
+ # String
1461
+ sample({ "a" => "16777217" }) do
1462
+ expect(subject.get("a")).to be_a(Float).and eq(1.6777217E7)
1463
+ end
1464
+ sample({ "a" => "16777217.0" }) do
1465
+ expect(subject.get("a")).to be_a(Float).and eq(1.6777217E7)
1466
+ end
1467
+ end
1468
+
1469
+
1470
+ context "2147483648" do
1471
+ # Long
1472
+ sample({ "a" => 2147483648 }) do
1473
+ expect(subject.get("a")).to be_a(Float).and eq(2.147483648E9)
1474
+ end
1475
+ # Double
1476
+ sample({ "a" => 2.147483648E9 }) do
1477
+ expect(subject.get("a")).to be_a(Float).and eq(2.147483648E9)
1478
+ end
1479
+ # String
1480
+ sample({ "a" => "2147483648" }) do
1481
+ expect(subject.get("a")).to be_a(Float).and eq(2.147483648E9)
1482
+ end
1483
+ sample({ "a" => "2147483648.0" }) do
1484
+ expect(subject.get("a")).to be_a(Float).and eq(2.147483648E9)
1485
+ end
1486
+ end
1487
+
1488
+ context "9007199254740993" do
1489
+ # Long
1490
+ sample({ "a" => 9007199254740993 }) do
1491
+ expect(subject.get("a")).to be_a(Float).and eq(9.007199254740992E15)
1492
+ end
1493
+ # String
1494
+ sample({ "a" => "9007199254740993" }) do
1495
+ expect(subject.get("a")).to be_a(Float).and eq(9.007199254740992E15)
1496
+ end
1497
+ sample({ "a" => "9007199254740993.0" }) do
1498
+ expect(subject.get("a")).to be_a(Float).and eq(9.007199254740992E15)
1499
+ end
1500
+ sample({ "a" => "9.007199254740993e+15" }) do
1501
+ expect(subject.get("a")).to be_a(Float).and eq(9007199254740992)
1502
+ end
1503
+ end
1504
+
1505
+ context "9223372036854775808" do
1506
+ # String
1507
+ sample({ "a" => "9223372036854775808" }) do
1508
+ expect(subject.get("a")).to be_a(Float).and eq(9.223372036854775808E18)
1509
+ end
1510
+ sample({ "a" => "9223372036854775808.0" }) do
1511
+ expect(subject.get("a")).to be_a(Float).and eq(9.223372036854775808E18)
1512
+ end
1513
+ end
1514
+
1515
+ context "680564693277057720000000000000000000000" do
1516
+ # String
1517
+ sample({ "a" => "680564693277057720000000000000000000000" }) do
1518
+ expect(subject.get("a")).to be_a(Float).and eq(6.805646932770577e+38)
1519
+ end
1520
+ sample({ "a" => "680564693277057720000000000000000000000.0" }) do
1521
+ expect(subject.get("a")).to be_a(Float).and eq(6.805646932770577e+38)
1522
+ end
1523
+ end
1524
+ end
1525
+
1526
+ end unless LogStash::Filters::Mutate.is_lenient_version? # only test type conversions in v8.14+
1527
+
1528
+ describe "parse_signed_hex_str" do
1529
+ subject { LogStash::Filters::Mutate.new({ }) }
1530
+
1531
+ context 'hexadecimal integers' do
1532
+ it 'parses positive hex integer' do
1533
+ expect(subject.send(:parse_signed_hex_str, '0x1A')).to eq(26.0)
1534
+ end
1535
+
1536
+ it 'parses negative hex integer' do
1537
+ expect(subject.send(:parse_signed_hex_str, '-0x1A')).to eq(-26.0)
1538
+ expect(subject.send(:parse_signed_hex_str,'-0xFF')).to eq(-255.0)
1539
+ end
1540
+
1541
+ it 'ignores case in hex prefix' do
1542
+ expect(subject.send(:parse_signed_hex_str,'0x1A')).to eq(26.0)
1543
+ expect(subject.send(:parse_signed_hex_str,'-0x1A')).to eq(-26.0)
1544
+ end
1545
+ end
1546
+
1547
+ context 'hexadecimal floats' do
1548
+ it 'parses positive hex float' do
1549
+ expect(subject.send(:parse_signed_hex_str,'0x1.8p+1')).to eq(3.0)
1550
+ end
1551
+
1552
+ it 'parses negative hex float' do
1553
+ expect(subject.send(:parse_signed_hex_str,'-0x1.8p+1')).to eq(-3.0)
1554
+ expect(subject.send(:parse_signed_hex_str,'-0x1.2p+2')).to eq(-4.5)
1555
+ end
1556
+ end
1557
+
1558
+ context 'non-hex strings' do
1559
+ it 'returns nil for decimal numbers' do
1560
+ expect(subject.send(:parse_signed_hex_str,'123')).to be_nil
1561
+ expect(subject.send(:parse_signed_hex_str,'-456')).to be_nil
1562
+ expect(subject.send(:parse_signed_hex_str,'1.23')).to be_nil
1563
+ end
1564
+
1565
+ it 'returns nil for random strings' do
1566
+ expect(subject.send(:parse_signed_hex_str,'abc')).to be_nil
1567
+ expect(subject.send(:parse_signed_hex_str,'0b1010')).to be_nil
1568
+ end
1569
+ end
1570
+ end unless LogStash::Filters::Mutate.is_lenient_version?
1571
+
1125
1572
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-filter-mutate
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.8
4
+ version: 3.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-11-22 00:00:00.000000000 Z
10
+ date: 2025-10-31 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
13
+ name: logstash-core-plugin-api
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - ">="
@@ -19,9 +19,8 @@ dependencies:
19
19
  - - "<="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '2.99'
22
- name: logstash-core-plugin-api
23
- prerelease: false
24
22
  type: :runtime
23
+ prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
26
25
  requirements:
27
26
  - - ">="
@@ -31,56 +30,56 @@ dependencies:
31
30
  - !ruby/object:Gem::Version
32
31
  version: '2.99'
33
32
  - !ruby/object:Gem::Dependency
33
+ name: logstash-patterns-core
34
34
  requirement: !ruby/object:Gem::Requirement
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
38
  version: '0'
39
- name: logstash-patterns-core
40
- prerelease: false
41
39
  type: :development
40
+ prerelease: false
42
41
  version_requirements: !ruby/object:Gem::Requirement
43
42
  requirements:
44
43
  - - ">="
45
44
  - !ruby/object:Gem::Version
46
45
  version: '0'
47
46
  - !ruby/object:Gem::Dependency
47
+ name: logstash-filter-grok
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
52
  version: '0'
53
- name: logstash-filter-grok
54
- prerelease: false
55
53
  type: :development
54
+ prerelease: false
56
55
  version_requirements: !ruby/object:Gem::Requirement
57
56
  requirements:
58
57
  - - ">="
59
58
  - !ruby/object:Gem::Version
60
59
  version: '0'
61
60
  - !ruby/object:Gem::Dependency
61
+ name: logstash-codec-plain
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
66
  version: '0'
67
- name: logstash-codec-plain
68
- prerelease: false
69
67
  type: :development
68
+ prerelease: false
70
69
  version_requirements: !ruby/object:Gem::Requirement
71
70
  requirements:
72
71
  - - ">="
73
72
  - !ruby/object:Gem::Version
74
73
  version: '0'
75
74
  - !ruby/object:Gem::Dependency
75
+ name: logstash-devutils
76
76
  requirement: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
- name: logstash-devutils
82
- prerelease: false
83
81
  type: :development
82
+ prerelease: false
84
83
  version_requirements: !ruby/object:Gem::Requirement
85
84
  requirements:
86
85
  - - ">="
@@ -111,7 +110,6 @@ licenses:
111
110
  metadata:
112
111
  logstash_plugin: 'true'
113
112
  logstash_group: filter
114
- post_install_message:
115
113
  rdoc_options: []
116
114
  require_paths:
117
115
  - lib
@@ -126,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
124
  - !ruby/object:Gem::Version
127
125
  version: '0'
128
126
  requirements: []
129
- rubygems_version: 3.2.33
130
- signing_key:
127
+ rubygems_version: 3.6.3
131
128
  specification_version: 4
132
129
  summary: Performs mutations on fields
133
130
  test_files: