MatchStep { public MatchStep(String raw) { boolean each = false; raw = raw.trim(); if (raw.startsWith("each")) { each = true; raw = raw.substring(4).trim(); } boolean contains = false; boolean not = false; boolean only = false; boolean any = false; boolean deep = false; int spacePos = raw.indexOf(' '); int leftParenPos = raw.indexOf('('); int rightParenPos = raw.indexOf(')'); int lhsEndPos = raw.indexOf(" contains"); if (lhsEndPos == -1) { lhsEndPos = raw.indexOf(" !contains"); } int searchPos = 0; int eqPos = raw.indexOf(" == "); if (eqPos == -1) { eqPos = raw.indexOf(" != "); } if (lhsEndPos != -1 && (eqPos == -1 || eqPos > lhsEndPos)) { contains = true; not = raw.charAt(lhsEndPos + 1) == '!'; searchPos = lhsEndPos + (not ? 10 : 9); String anyOrOnlyOrDeep = raw.substring(searchPos).trim(); if (anyOrOnlyOrDeep.startsWith("only")) { int onlyPos = raw.indexOf(" only", searchPos); only = true; searchPos = onlyPos + 5; } else if (anyOrOnlyOrDeep.startsWith("any")) { int anyPos = raw.indexOf(" any", searchPos); any = true; searchPos = anyPos + 4; } else if (anyOrOnlyOrDeep.startsWith("deep")) { int deepPos = raw.indexOf(" deep", searchPos); deep = true; searchPos = deepPos + 5; } } else { int equalPos = raw.indexOf(" ==", searchPos); int notEqualPos = raw.indexOf(" !=", searchPos); if (equalPos == -1 && notEqualPos == -1) { throw new RuntimeException("syntax error, expected '==' for match"); } lhsEndPos = min(equalPos, notEqualPos); if (lhsEndPos > spacePos && rightParenPos != -1 && rightParenPos > lhsEndPos && rightParenPos < leftParenPos) { equalPos = raw.indexOf(" ==", rightParenPos); notEqualPos = raw.indexOf(" !=", rightParenPos); if (equalPos == -1 && notEqualPos == -1) { throw new RuntimeException("syntax error, expected '==' for match"); } lhsEndPos = min(equalPos, notEqualPos); } not = lhsEndPos == notEqualPos; searchPos = lhsEndPos + 3; } String lhs = raw.substring(0, lhsEndPos).trim(); if (leftParenPos == -1) { leftParenPos = lhs.indexOf('['); } if (spacePos != -1 && (leftParenPos > spacePos || leftParenPos == -1)) { name = lhs.substring(0, spacePos); path = StringUtils.trimToNull(lhs.substring(spacePos)); } else { name = lhs; path = null; } expected = StringUtils.trimToNull(raw.substring(searchPos)); type = getType(each, not, contains, only, any, deep); } MatchStep(String raw);  final String name; final String path; final MatchType type; final String expected; }
@Test public void testMatchStep() { test("aXml test("hello ==", EQUALS, "hello", null, null); test("hello world == foo", EQUALS, "hello", "world", "foo"); test("each hello world == foo", EACH_EQUALS, "hello", "world", "foo"); test("hello.foo(bar) != blah", NOT_EQUALS, "hello.foo(bar)", null, "blah"); test("foo count(/records test("__arg == karate.get('foos[' + __loop + ']')", EQUALS, "__arg", null, "karate.get('foos[' + __loop + ']')"); test("response $[?(@.b=='ab')] == '#[1]'", EQUALS, "response", "$[?(@.b=='ab')]", "'#[1]'"); test("test != '#? _.length == 2'", NOT_EQUALS, "test", null, "'#? _.length == 2'"); test("actual[0] !contains badSchema", NOT_CONTAINS, "actual[0]", null, "badSchema"); test("actual[0] contains badSchema", CONTAINS, "actual[0]", null, "badSchema"); test("driver.eval('{ foo: \"bar\" }') == { hello: 'world' }", EQUALS, "driver.eval('{ foo: \"bar\" }')", null, "{ hello: 'world' }"); test("response.integration.serviceData['Usage Data'][0].Stage ==", EQUALS, "response.integration.serviceData['Usage Data'][0].Stage", null, null); test("response contains { foo: 'a any b' }", CONTAINS, "response", null, "{ foo: 'a any b' }"); test("response.foo == 'a contains b'", EQUALS, "response.foo", null, "'a contains b'"); test("$.addOns[?(@.entitlementStateChangeReason=='RESUBSCRIBE')].addOnOfferID contains only toAddOnOfferIDs", CONTAINS_ONLY, "$.addOns[?(@.entitlementStateChangeReason=='RESUBSCRIBE')].addOnOfferID", null, "toAddOnOfferIDs"); }