Repository: authorjapps/zerocode
Pull request #270 (2019-07-05 10:15:10)

ISS-67 # Add '$ONE.OF:' functionality
Fixed formatting issues and added integration tests to http-testing module as requested. 

Sorry for the confusion guys, I thought I'd pulled before pushing my changes but clearly not. I think it's ok now.




Patch:
diff --git a/README.md b/README.md
index 90ac66c1..60479835 100644
--- a/README.md
+++ b/README.md
@@ -2237,6 +2237,7 @@ See below both the examples( See this in the hello-world repo in action i.e. the
 | $MATCHES.STRING:`\\d{4}-\\d{2}-\\d{2}`       | Assertion passes if the response value contains e.g. `"1989-07-09"` matching regex `\\d{4}-\\d{2}-\\d{2}` | Otherwise fails |
 | $LOCAL.DATETIME.BEFORE:2017-09-14T09:49:34.000Z       | Assertion passes if the actual date is earlier than this date | Otherwise fails |
 | $LOCAL.DATETIME.AFTER:2016-09-14T09:49:34.000Z       | Assertion passes if the actual date is later than this date | Otherwise fails |
+| $ONE.OF:[First Val, Second Val, Nth Val]       | Assertion passes if `currentStatus` actual value is one of the expected values supplied in the `array` | Otherwise fails. E.g. `"currentStatus": "$ONE.OF:[Found, Searching, Not Found]"` |
 
 #### Assertion Path holders
 
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/FieldIsOneOfValueAsserter.java b/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/FieldIsOneOfValueAsserter.java
new file mode 100644
index 00000000..53abd25a
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/FieldIsOneOfValueAsserter.java
@@ -0,0 +1,66 @@
+package org.jsmart.zerocode.core.engine.assertion;
+
+import java.util.Arrays;
+
+import static org.apache.commons.lang.StringUtils.substringBetween;
+
+public class FieldIsOneOfValueAsserter implements JsonAsserter {
+	private final String path;
+	final Object expected;
+
+	@Override
+	public String getPath() {
+		return path;
+	}
+
+	@Override
+	public AssertionReport actualEqualsToExpected(Object actualResult) {
+		boolean areEqual;
+
+		if (expected != null) {
+            String expectedString = substringBetween((String) expected, "[", "]");
+
+			// Store collection as a java array
+			String[] expectedArray = null;
+			
+			// Check if it's an empty json array
+			if (!expectedString.isEmpty()) {
+				// Split into an array
+				expectedArray = expectedString.split(",");
+			} else {
+				expectedArray = new String[] {};
+			}
+				
+			// Remove leading and trailing spaces
+			for (int i = 0; i < expectedArray.length; i++) {
+				// Checking that this is not a whitespace string (cannot use .isBlank() as we're
+				// targeting java 1.8)
+				if (!expectedArray[i].trim().isEmpty())
+					expectedArray[i] = expectedArray[i].trim();
+			}
+
+			if (actualResult != null) {
+				// Search list for value
+				areEqual = Arrays.asList(expectedArray).contains(actualResult);
+			} else {
+				areEqual = false;
+			}
+		} else {
+			// Both null
+			if (actualResult == null) {
+				areEqual = true;
+			} else {
+				areEqual = false;
+			}
+		}
+
+		return areEqual ? AssertionReport.createFieldMatchesReport()
+				: AssertionReport.createFieldDoesNotMatchReport(path, "One Of:" + expected, actualResult);
+	}
+
+	public FieldIsOneOfValueAsserter(String path, Object expected) {
+		this.path = path;
+		this.expected = expected;
+	}
+
+}
\ No newline at end of file


Test patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
index 52c89889..0d819bda 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
@@ -45,6 +45,7 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
     public static final String ASSERT_VALUE_LESSER_THAN = "$LT.";
     public static final String ASSERT_LOCAL_DATETIME_AFTER = "$LOCAL.DATETIME.AFTER:";
     public static final String ASSERT_LOCAL_DATETIME_BEFORE = "$LOCAL.DATETIME.BEFORE:";
+    public static final String ASSERT_VALUE_ONE_OF = "$ONE.OF:";
     public static final String ASSERT_PATH_VALUE_NODE = "$";
     public static final String RAW_BODY = ".rawBody";
 
@@ -204,6 +205,9 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
                 }else if (value instanceof String && (value.toString()).startsWith(ASSERT_LOCAL_DATETIME_BEFORE)) {
                     String expected = ((String) value).substring(ASSERT_LOCAL_DATETIME_BEFORE.length());
                     asserter = new FieldHasDateBeforeValueAsserter(path, parseLocalDateTime(expected));
+                }else if (value instanceof String && (value.toString()).startsWith(ASSERT_VALUE_ONE_OF)) {
+                    String expected = ((String) value).substring(ASSERT_VALUE_ONE_OF.length());
+                    asserter = new FieldIsOneOfValueAsserter(path, expected);
                 }
                 else {
                     asserter = new FieldHasExactValueAsserter(path, value);
diff --git a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
index 8bec24ba..f4963f1a 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
@@ -845,4 +845,165 @@ public class ZeroCodeJsonTestProcesorImplTest {
                 is("Assertion path '$.body.projectDetails.startDateTime' with actual value '2015-09-14T09:49:34.000Z' "
                 		+ "did not match the expected value 'Date Before:2015-09-14T09:49:34'"));
     }
+    
+    @Test
+    public void testValueOneOf_ValuePresent() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_currentStatus.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[Found, Searching, Not Looking]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "        \"currentStatus\": \"Searching\"\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(0));
+    }
+    
+    @Test
+    public void testValueOneOf_ValueNotPresent() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_currentStatus.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[Found, Searching, Not Looking]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "        \"currentStatus\": \"Quit\"\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(1));
+    }
+    
+    @Test
+    public void testValueOneOf_ActualResultNull() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_currentStatus.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[Found, Searching, Not Looking]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(1));
+    }
+    
+    @Test
+    public void testValueOneOf_MatchEmptyString() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_emptyString.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[Found, Searching,, Not Looking]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "        \"currentStatus\": \"\"\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(0));
+    }
+    
+    @Test
+    public void testValueOneOf_MatchWhiteSpace() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_whiteSpace.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[Found, Searching, , Not Looking]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "        \"currentStatus\": \" \"\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(0));
+    }
+    
+    @Test
+    public void testValueOneOf_ExpectedArrayEmpty() throws Exception {
+        ScenarioSpec scenarioSpec = smartUtils.jsonFileToJava(
+                "one_of/oneOf_test_expectedArrayEmpty.json",
+                ScenarioSpec.class);
+
+        final String assertionsSectionAsString = scenarioSpec.getSteps().get(0).getAssertions().toString();
+        String mockScenarioState = "{}";
+
+        final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
+        assertThat(resolvedAssertions, containsString("\"currentStatus\":\"$ONE.OF:[]\""));
+        	
+        	
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
+        assertThat(asserters.size(), is(2));
+
+        String mockTestResponse = "{\n" +
+                "    \"status\": 200,\n" +
+                "    \"body\": {\n" +
+                "        \"currentStatus\": \"Searching\"\n" +
+                "    }\n" +
+                "}";
+        List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, mockTestResponse);
+
+        assertThat(failedReports.size(), is(1));
+    }
 }
\ No newline at end of file
diff --git a/core/src/test/resources/one_of/oneOf_test_currentStatus.json b/core/src/test/resources/one_of/oneOf_test_currentStatus.json
new file mode 100644
index 00000000..1297c701
--- /dev/null
+++ b/core/src/test/resources/one_of/oneOf_test_currentStatus.json
@@ -0,0 +1,18 @@
+{
+    "scenarioName": "Assert that 'currentStatus' is one of array items",
+    "steps": [
+        {
+            "name": "get_person_job_details",
+            "url": "",
+            "operation": "",
+            "request": {
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                	"currentStatus": "$ONE.OF:[Found, Searching, Not Looking]"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/src/test/resources/one_of/oneOf_test_emptyString.json b/core/src/test/resources/one_of/oneOf_test_emptyString.json
new file mode 100644
index 00000000..c1dae050
--- /dev/null
+++ b/core/src/test/resources/one_of/oneOf_test_emptyString.json
@@ -0,0 +1,18 @@
+{
+    "scenarioName": "Assert that 'currentStatus' is one of array items, including an empty string",
+    "steps": [
+        {
+            "name": "get_person_job_details",
+            "url": "",
+            "operation": "",
+            "request": {
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                	"currentStatus": "$ONE.OF:[Found, Searching,, Not Looking]"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/src/test/resources/one_of/oneOf_test_expectedArrayEmpty.json b/core/src/test/resources/one_of/oneOf_test_expectedArrayEmpty.json
new file mode 100644
index 00000000..663ffbd8
--- /dev/null
+++ b/core/src/test/resources/one_of/oneOf_test_expectedArrayEmpty.json
@@ -0,0 +1,18 @@
+{
+    "scenarioName": "Assert that 'currentStatus' is one of array items which is empty",
+    "steps": [
+        {
+            "name": "get_person_job_details",
+            "url": "",
+            "operation": "",
+            "request": {
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                	"currentStatus": "$ONE.OF:[]"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/core/src/test/resources/one_of/oneOf_test_whiteSpace.json b/core/src/test/resources/one_of/oneOf_test_whiteSpace.json
new file mode 100644
index 00000000..e3ae05cf
--- /dev/null
+++ b/core/src/test/resources/one_of/oneOf_test_whiteSpace.json
@@ -0,0 +1,18 @@
+{
+    "scenarioName": "Assert that 'currentStatus' is one of array items, including a whitespace",
+    "steps": [
+        {
+            "name": "get_person_job_details",
+            "url": "",
+            "operation": "",
+            "request": {
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                	"currentStatus": "$ONE.OF:[Found, Searching, , Not Looking]"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldoneof/HelloWorldOneOfTest.java b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldoneof/HelloWorldOneOfTest.java
new file mode 100644
index 00000000..30491ce3
--- /dev/null
+++ b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworldoneof/HelloWorldOneOfTest.java
@@ -0,0 +1,18 @@
+package org.jsmart.zerocode.testhelp.tests.helloworldoneof;
+
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("github_host.properties")
+@RunWith(ZeroCodeUnitRunner.class)
+public class HelloWorldOneOfTest {
+
+    @Test
+    @JsonTestCase("helloworld_one_of/hello_world_one_of_test.json")
+    public void testValueOneOf() throws Exception {
+
+    }
+}
diff --git a/http-testing/src/test/resources/helloworld_one_of/hello_world_one_of_test.json b/http-testing/src/test/resources/helloworld_one_of/hello_world_one_of_test.json
new file mode 100644
index 00000000..cc02beac
--- /dev/null
+++ b/http-testing/src/test/resources/helloworld_one_of/hello_world_one_of_test.json
@@ -0,0 +1,31 @@
+{
+    "scenarioName": "Assert that value is one of the items in the array",
+    "steps": [
+        {
+            "name": "match_user_location",
+            "url": "/users/octocat",
+            "operation": "GET",
+            "request": {
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                    "location" : "$ONE.OF:[San Francisco, New York, Seattle]"
+                }
+            }
+        },
+		{
+            	"name": "match_user_gravatar_id_empty_string",
+	            "url": "/users/octocat",
+	            "operation": "GET",
+	            "request": {
+	            },
+	            "assertions": {
+	                "status": 200,
+	                "body": {
+	                    "gravatar_id" : "$ONE.OF:[-1,, 0]"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file