Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions src/jsonata/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,18 @@ def validate_input(arg: Optional[Any]) -> None:
#
@staticmethod
def substring(string: Optional[str], start: Optional[float], length: Optional[float]) -> Optional[str]:
if string is utils.Utils.NULL_VALUE or start is utils.Utils.NULL_VALUE or length is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

# undefined inputs always return undefined
if string is None:
return None

if string is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)
# match JS: undefined start returns the whole string, or "" if a length is given
if start is None:
return string if length is None else ""

start = int(start) if start is not None else None
start = int(start)
length = int(length) if length is not None else None

# not used: var strArray = stringToArray(string)
Expand Down Expand Up @@ -308,13 +312,13 @@ def substr(string: str, start: int, length: int) -> str:
#
@staticmethod
def substring_before(string: Optional[str], chars: Optional[str]) -> Optional[str]:
if string is utils.Utils.NULL_VALUE or chars is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

# undefined inputs always return undefined
if string is None:
return None

if string is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

if chars is None:
return string

Expand All @@ -332,12 +336,15 @@ def substring_before(string: Optional[str], chars: Optional[str]) -> Optional[st
#
@staticmethod
def substring_after(string: Optional[str], chars: Optional[str]) -> Optional[str]:
if string is utils.Utils.NULL_VALUE or chars is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

# undefined inputs always return undefined
if string is None:
return None

if string is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)
if chars is None:
return string

pos = string.find(chars)
if pos > -1:
Expand Down Expand Up @@ -433,22 +440,25 @@ def trim(string: Optional[str]) -> Optional[str]:
#
@staticmethod
def pad(string: Optional[str], width: Optional[int], char: Optional[str]) -> Optional[str]:
if string is utils.Utils.NULL_VALUE or width is utils.Utils.NULL_VALUE or char is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

# undefined inputs always return undefined
if string is None:
return None

if string is utils.Utils.NULL_VALUE:
raise jexception.JException("T0410", -1)

if char is None or not char:
char = " "

# match JS: undefined width adds no padding
if width is None:
return string

# match JS: truncate width to integer
if width is not None:
try:
width = int(width)
except Exception:
width = 0
try:
width = int(width)
except Exception:
width = 0

if width < 0:
result = Functions.left_pad(string, -width, char)
Expand Down
18 changes: 18 additions & 0 deletions tests/string_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
锘縤mport jsonata
import pytest
from jsonata.regex_engine import default_regex_engine


Expand Down Expand Up @@ -147,6 +148,23 @@ def test_trim(self):
assert jsonata.Jsonata("$trim(\"\")").evaluate(None) == ""
assert jsonata.Jsonata("$trim(notthere)").evaluate(None) is None

def test_undefined_args(self):
assert jsonata.Jsonata("$substring('abc', $nothing)").evaluate(None) == "abc"
assert jsonata.Jsonata("$substring('abc', $nothing, 1)").evaluate(None) == ""
assert jsonata.Jsonata("$substring(?, $nothing)('abc')").evaluate(None) == "abc"
assert jsonata.Jsonata("$substringAfter('abc', $nothing)").evaluate(None) == "abc"
assert jsonata.Jsonata("$pad('abc', $nothing)").evaluate(None) == "abc"

def test_null_args(self):
for expr in ["$substring('abc', null)", "$substring('abc', 1, null)", "$substring('abc', $nothing, null)",
"$substring($nothing, null)", "$substring($nothing, 1, null)",
"$pad('abc', null)", "$pad('abc', 5, null)", "$pad($nothing, null)",
"$substringBefore('abc', null)", "$substringBefore($nothing, null)",
"$substringAfter('abc', null)", "$substringAfter($nothing, null)"]:
with pytest.raises(jsonata.JException) as exc_info:
jsonata.Jsonata(expr).evaluate(None)
assert exc_info.value.error == "T0410"

def test_match_limit(self):
res = jsonata.Jsonata("$match('ababab', /ab/)").evaluate(None)
assert res is not None
Expand Down
Loading