From 74a47154f3bce495d9f58a300a860d750ae309f1 Mon Sep 17 00:00:00 2001 From: danielhanrahan Date: Wed, 28 Jun 2023 12:55:20 +0100 Subject: Apostrophe handling in CpsPathParser Apostrophe is not currently handled correctly, and having apostrophe in the xpath will lead to various errors. For example, normalizing this xpath works: /path[@name="I'm quoted"] -> /path[@name='I\'m quoted'] However the resulting xpath will throw a PathParsingException if parsed! (Thus path normalization is not idempotent.) - Use '' for escaping apostrophe in single quoted leaf value, to comply with XPath standard (and use "" for escaping in "). - Use Liquibase to make existing data comply with new rules. - Leaf values in data leaves are now unescaped, e.g. "I'm quoted" - Quoting is now consistent for leaf/text/contains conditions. Issue-ID: CPS-1769 Signed-off-by: danielhanrahan Change-Id: Iafc287f738254d7f99706c6bc548091c0ecd5aa0 --- .../functional/CpsQueryServiceIntegrationSpec.groovy | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'integration-test') diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy index 53737fba8..74496d301 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsQueryServiceIntegrationSpec.groovy @@ -356,4 +356,23 @@ class CpsQueryServiceIntegrationSpec extends FunctionalSpecBase { 'text-condition' || "/bookstore/categories[@code='1']/books/title[text()='[@hello=world]']" 'contains-condition' || "/bookstore/categories[@code='1']/books[contains(@title, '[@hello=world]')]" } + + def 'Cps Path get and query can handle apostrophe inside #quotes.'() { + given: 'a book with special characters in title' + cpsDataService.saveData(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, "/bookstore/categories[@code='1']", + '{"books": [ {"title":"I\'m escaping"} ] }', OffsetDateTime.now()) + when: 'a query is executed' + def result = objectUnderTest.queryDataNodes(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, cpsPath, OMIT_DESCENDANTS) + then: 'the node is returned' + assert result.size() == 1 + assert result[0].xpath == "/bookstore/categories[@code='1']/books[@title='I''m escaping']" + cleanup: 'the new datanode' + cpsDataService.deleteDataNode(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, "/bookstore/categories[@code='1']/books[@title='I''m escaping']", OffsetDateTime.now()) + where: + quotes || cpsPath + 'single quotes' || "/bookstore/categories[@code='1']/books[@title='I''m escaping']" + 'double quotes' || '/bookstore/categories[@code="1"]/books[@title="I\'m escaping"]' + 'text-condition' || "/bookstore/categories[@code='1']/books/title[text()='I''m escaping']" + 'contains-condition' || "/bookstore/categories[@code='1']/books[contains(@title, 'I''m escaping')]" + } } -- cgit 1.2.3-korg