Files
ResInsight/GrpcInterface/Python/rips/tests/test_makelist_parsing.py
T
Kristian Bendiksen 00b4f180a2 #13515 Fix comma-aware parsing of gRPC string values in Python
Replace naive split(", ") in __makelist() with a quote-aware state
machine that respects quoted strings and nested brackets. Also add
__unescape_string() to reverse C++ escaping, and fix strip('"') to
only remove the outer quote pair.
2026-03-06 20:56:48 +01:00

153 lines
5.7 KiB
Python

"""
Tests for PdmObjectBase.__makelist() and __convert_from_grpc_value() parsing.
These tests verify quote-aware parsing of gRPC string values, including
strings containing commas, escaped quotes, nested lists, and schedule text.
Regression tests for #13515.
"""
import sys
import os
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from rips.pdmobject import PdmObjectBase
@pytest.fixture
def parser():
"""Create a PdmObjectBase instance for testing parsing methods."""
return PdmObjectBase(pb2_object=None, channel=None)
class TestEmptyAndSimpleLists:
"""Tests for basic list parsing."""
def test_empty_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[]")
assert result == []
def test_single_int(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[42]")
assert result == [42]
def test_int_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[1, 2, 3]")
assert result == [1, 2, 3]
def test_float_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[1.5, 2.5, 3.5]")
assert result == [1.5, 2.5, 3.5]
def test_bool_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[true, false, true]")
assert result == [True, False, True]
def test_simple_string_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value('["hello", "world"]')
assert result == ["hello", "world"]
class TestStringsWithCommas:
"""Core regression tests for #13515: strings containing commas."""
def test_single_string_with_comma(self, parser):
# C++ sends: ["hello, world"]
result = parser._PdmObjectBase__convert_from_grpc_value('["hello, world"]')
assert result == ["hello, world"]
def test_multiple_strings_with_commas(self, parser):
# C++ sends: ["a, b", "c, d"]
result = parser._PdmObjectBase__convert_from_grpc_value('["a, b", "c, d"]')
assert result == ["a, b", "c, d"]
def test_string_with_multiple_commas(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value(
'["one, two, three, four"]'
)
assert result == ["one, two, three, four"]
def test_mixed_strings_with_and_without_commas(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value(
'["no comma", "has, comma", "also none"]'
)
assert result == ["no comma", "has, comma", "also none"]
class TestEscapedCharacters:
"""Tests for escaped quotes and backslashes inside strings."""
def test_escaped_quote_in_string(self, parser):
# C++ sends: ["say \"hello\""] -> Python should get: say "hello"
result = parser._PdmObjectBase__convert_from_grpc_value('["say \\"hello\\""]')
assert result == ['say "hello"']
def test_escaped_backslash_in_string(self, parser):
# C++ sends: ["path\\to\\file"] -> Python should get: path\to\file
result = parser._PdmObjectBase__convert_from_grpc_value(
'["path\\\\to\\\\file"]'
)
assert result == ["path\\to\\file"]
def test_escaped_quote_and_comma(self, parser):
# C++ sends: ["say \"hi\", bye"] -> Python should get: say "hi", bye
result = parser._PdmObjectBase__convert_from_grpc_value('["say \\"hi\\", bye"]')
assert result == ['say "hi", bye']
def test_scalar_string_unescape(self, parser):
# A scalar (non-list) string with escaped characters
result = parser._PdmObjectBase__convert_from_grpc_value('"say \\"hello\\""')
assert result == 'say "hello"'
def test_scalar_string_unescape_backslash(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value(
'"C:\\\\Users\\\\file.txt"'
)
assert result == "C:\\Users\\file.txt"
class TestNestedLists:
"""Tests for nested list parsing."""
def test_nested_int_lists(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value("[[1, 2], [3, 4]]")
assert result == [[1, 2], [3, 4]]
def test_nested_string_lists_with_commas(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value(
'[["a, b", "c"], ["d", "e, f"]]'
)
assert result == [["a, b", "c"], ["d", "e, f"]]
class TestMixedTypes:
"""Tests for lists with mixed types."""
def test_mixed_type_list(self, parser):
result = parser._PdmObjectBase__convert_from_grpc_value(
'[1, "text, with comma", 3.5, true]'
)
assert result == [1, "text, with comma", 3.5, True]
class TestScheduleTextRegression:
"""Regression test for schedule text containing COMPDAT with commas."""
def test_schedule_text_single_string_not_split(self, parser):
# Schedule text is a single string containing many commas
# C++ wraps it in quotes: ["COMPDAT\n 'Well' 1 2 3 /\n/"]
schedule = "COMPDAT\n 'WellA' 10 20 30 40 OPEN 1* 0.1 4* 0.5 /\n/"
grpc_value = '["' + schedule.replace("\\", "\\\\").replace('"', '\\"') + '"]'
result = parser._PdmObjectBase__convert_from_grpc_value(grpc_value)
assert len(result) == 1
assert result[0] == schedule
def test_compdat_with_commas_in_comments(self, parser):
# A COMPDAT string that contains commas in inline comments
text = "COMPDAT -- well completions, zone A, zone B\n 'Well' 1 2 3 /\n/"
grpc_value = '["' + text.replace("\\", "\\\\").replace('"', '\\"') + '"]'
result = parser._PdmObjectBase__convert_from_grpc_value(grpc_value)
assert len(result) == 1
assert result[0] == text