/*
* Copyright 2013, The Sporting Exchange Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.betfair.testing.utils.cougar.assertions;
import com.betfair.testing.utils.cougar.misc.AggregatedStepExpectedOutputMetaData;
import com.betfair.testing.utils.cougar.misc.DataTypeEnum;
import com.betfair.testing.utils.cougar.misc.ObjectUtil;
import com.betfair.testing.utils.cougar.misc.StepMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class LinkedHashMapAssertion implements IAssertion {
@Override
//public HashMap preProcess(TestStepBean bean) throws JETTFailFastException {
public LinkedHashMap<Object, Object> preProcess(Object actualObject, AggregatedStepExpectedOutputMetaData expMetaData) throws AssertionError {
if (expMetaData == null) {
return null;
}
if (expMetaData.size() == 0) {
return new LinkedHashMap<Object, Object>();
}
LinkedHashMap<Object, Object> expectedResultsMap;
Boolean isExpectedResultAlreadyLinkedHashMap = false;
if (expMetaData.getMetaDataAtIndex(0).size() == 1) {
if ((expMetaData.getMetaDataAtIndex(0).getValueAtIndex(0)==null) || (expMetaData.getMetaDataAtIndex(0).getValueAtIndex(0).getClass().equals(LinkedHashMap.class))) {
isExpectedResultAlreadyLinkedHashMap = true;
}
}
if (isExpectedResultAlreadyLinkedHashMap) {
//expectedResultsMap = (HashMap<String, Object>)bean.getExpectedOutputMetaData().getMetaDataAtIndex(0).getValueAtIndex(0);
return (LinkedHashMap<Object, Object>)expMetaData.getMetaDataAtIndex(0).getValueAtIndex(0);
} else {
HashMap actualHashMap = (LinkedHashMap)actualObject;
expectedResultsMap = new LinkedHashMap<Object, Object>();
//Bit poor but have to ensure all objects are of the same type
Boolean allContainedObjectsTheSame = true;
Class currentClass = null;
Class previousClass = null;
for (Object keyObject: actualHashMap.keySet()) {
String key = keyObject.toString();
if (actualHashMap.get(key) != null) {
currentClass = actualHashMap.get(key).getClass();
if (previousClass != null) {
if (previousClass != currentClass) {
allContainedObjectsTheSame = false;
break;
}
}
previousClass = currentClass;
} else {
/*If item is null, then cannot guarentee that it is the same type as
other objects*/
allContainedObjectsTheSame = false;
break;
}
}
StepMetaData stepMetaData = expMetaData.getMetaDataAtIndex(0);
if ((actualHashMap.size()!=0) && (allContainedObjectsTheSame)) {
DataTypeEnum type = ObjectUtil.resolveType(currentClass);
switch(type) {
case JAVA_DOT_LANG_OBJECT:
case STRING:
for (int i = 0; i < stepMetaData.size(); i++) {
Object castedExpectedObj = Reflect.getWrappedValue(currentClass, stepMetaData.getValueAtIndex(i));
expectedResultsMap.put(stepMetaData.getNameAtIndex(i),castedExpectedObj);
}
break;
default:
//If a complex object have to assume it is already casted as we cannot do it here
for (int i = 0; i < stepMetaData.size(); i++) {
expectedResultsMap.put(stepMetaData.getNameAtIndex(i), stepMetaData.getValueAtIndex(i));
}
break;
}
} else {
for (int i = 0; i < stepMetaData.size(); i++) {
expectedResultsMap.put(stepMetaData.getNameAtIndex(i), stepMetaData.getValueAtIndex(i));
}
}
}
return expectedResultsMap;
}
public void execute(String message, Object passedExpObject, Object passedActObject, AggregatedStepExpectedOutputMetaData outputMetaData) throws AssertionError {
executeSpecifiedKeysOnlyOrdered(passedExpObject, passedActObject, outputMetaData);
}
private void executeSpecifiedKeysOnlyOrdered(Object passedExpObject, Object passedActObject, AggregatedStepExpectedOutputMetaData outputMetaData) throws AssertionError {
/*
* Get a local version of the expected and actual object casted to
* correct type
*/
/*Map<String, Object> localExpectedResponse = (Map<String, Object>) bean.getTransformedExpectedResponse();
Map localActualResponse = (Map<String, Object>) bean.getActualResponse();*/
LinkedHashMap<Object, Object> expectedMap = (LinkedHashMap<Object, Object>) passedExpObject;
LinkedHashMap<Object, Object> actualMap = (LinkedHashMap<Object, Object>) passedActObject;
if ((expectedMap == null) || (actualMap == null)) {
AssertionUtils.jettAssertEquals("Checking LinkedHashMap: ", expectedMap, actualMap);
return;
}
DataTypeEnum keyType = null;
Class<?> keyClass = null;
if (actualMap.size() > 0) {
Set<Object> keySet = actualMap.keySet();
for(Object key: keySet) {
if (keyClass == null) {
keyClass = key.getClass();
} else {
if (key.getClass().isAssignableFrom(keyClass)) {
keyClass = key.getClass();
} else if (keyClass.isAssignableFrom(key.getClass())) {
//Ok
} else {
throw new AssertionError("JETT can only assert maps where keys have the same class");
}
}
}
keyType = ObjectUtil.resolveType(keyClass);
}
//Check keys order
List<Object> actKeys = new ArrayList<Object>();
for (Object actKey: actualMap.keySet()) {
actKeys.add(actKey);
}
Map<Object, Object> castedKeysMap = new LinkedHashMap<Object, Object>();
int actualKeyPreviousPos = Integer.MIN_VALUE;
Object previousKey = null;
for (Object expKey: expectedMap.keySet()) {
String compareMessage = "Checking LinkedHashMap ";
Object castedExpKey;
switch (keyType) {
case JAVA_DOT_LANG_OBJECT:
case STRING:
castedExpKey = Reflect.getWrappedValue(keyClass, expKey);
break;
default:
try {
castedExpKey = keyClass.cast(expKey);
} catch (ClassCastException e) {
AssertionUtils.actionFail(compareMessage + " - Unable to cast expected key '" + expKey.toString() + "' to the class of actual keys '" + keyClass + "'");
continue;
}
break;
}
castedKeysMap.put(castedExpKey, expectedMap.get(expKey));
if (actKeys.contains(castedExpKey)) {
int actualKeyPosition = actKeys.indexOf(castedExpKey);
if (actualKeyPreviousPos != Integer.MIN_VALUE) {
if (actualKeyPosition <= actualKeyPreviousPos) {
AssertionUtils.actionFail(compareMessage + "- Key order not as expected in LinkedHashMap - '" + castedExpKey + "' did not follow '" + previousKey + "'");
} else {
AssertionUtils.actionPass(compareMessage + "- Key order as expected in LinkedHashMap - '" + castedExpKey + "' followed '" + previousKey + "'");
}
}
actualKeyPreviousPos = actualKeyPosition;
previousKey = castedExpKey;
} else {
AssertionUtils.actionFail(compareMessage + "- Key not present in LinkedHashMap: '" + castedExpKey + "'");
}
}
for (Object castedExpKey : castedKeysMap.keySet()) {
String compareMessage = "Checking LinkedHashMap Entry for Key '" + castedExpKey.toString() + "' ";
if (!actualMap.containsKey(castedExpKey)) {
//Failure already reported above
continue;
}
Object expectedObj = castedKeysMap.get(castedExpKey);
Object actualObj = actualMap.get(castedExpKey);
if (expectedObj==null) {
AssertionUtils.jettAssertNull(compareMessage + "expected object is null, check if actual object is null.",actualObj);
} else if (actualObj==null) {
AssertionUtils.jettAssertNull(compareMessage + "actual is object is null, checking if expected object is null.",expectedObj);
} else {
DataTypeEnum type;
type = ObjectUtil.resolveType(actualObj);
switch(type) {
case JAVA_DOT_LANG_OBJECT:
case STRING:
Object castedExpectedObj = Reflect.getWrappedValue(actualObj.getClass(), expectedObj);
AssertionUtils.jettAssertEquals(compareMessage, castedExpectedObj, actualObj);
break;
default:
AssertionUtils.actionPass(compareMessage + "- Key Present - Checking values:");
IAssertion assertionProcessor = AssertionProcessorFactory.getAssertionProcessor(type);
assertionProcessor.execute(compareMessage, expectedObj, actualObj, null);
break;
}
}
}
}
private void executeAllKeysOrdered(Object passedExpObject, Object passedActObject, AggregatedStepExpectedOutputMetaData outputMetaData) throws AssertionError {
/*
* Get a local version of the expected and actual object casted to
* correct type
*/
/*Map<String, Object> localExpectedResponse = (Map<String, Object>) bean.getTransformedExpectedResponse();
Map localActualResponse = (Map<String, Object>) bean.getActualResponse();*/
LinkedHashMap<Object, Object> expectedMap = (LinkedHashMap<Object, Object>) passedExpObject;
LinkedHashMap<Object, Object> actualMap = (LinkedHashMap<Object, Object>) passedActObject;
if ((expectedMap == null) || (actualMap == null)) {
AssertionUtils.jettAssertEquals("Checking LinkedHashMap: ", expectedMap, actualMap);
return;
}
DataTypeEnum keyType = null;
Class<?> keyClass = null;
if (actualMap.size() > 0) {
Set<Object> keySet = actualMap.keySet();
for(Object key: keySet) {
if (keyClass == null) {
keyClass = key.getClass();
} else {
if (key.getClass().isAssignableFrom(keyClass)) {
keyClass = key.getClass();
} else if (keyClass.isAssignableFrom(key.getClass())) {
//Ok
} else {
throw new AssertionError("JETT can only assert maps where keys have the same class");
}
}
}
keyType = ObjectUtil.resolveType(keyClass);
}
//Check keys order
List<Object> actKeys = new ArrayList<Object>();
for (Object actKey: actualMap.keySet()) {
actKeys.add(actKey);
}
Map<Object, Object> castedKeysMap = new LinkedHashMap<Object, Object>();
int keyCounter = 0;
for (Object expKey: expectedMap.keySet()) {
String compareMessage = "Checking LinkedHashMap Key at position " + keyCounter;
Object castedExpKey;
switch (keyType) {
case JAVA_DOT_LANG_OBJECT:
case STRING:
castedExpKey = Reflect.getWrappedValue(keyClass, expKey);
break;
default:
try {
castedExpKey = keyClass.cast(expKey);
} catch (ClassCastException e) {
AssertionUtils.actionFail(compareMessage + ": Unable to cast expected key '" + expKey.toString() + "' to the class of actual keys '" + keyClass + "'");
continue;
}
break;
}
castedKeysMap.put(castedExpKey, expectedMap.get(expKey));
if (actKeys.size() > keyCounter) {
AssertionUtils.jettAssertEquals(compareMessage, castedExpKey, actKeys.get(keyCounter));
} else {
AssertionUtils.actionFail(compareMessage + ": No actual key present at position " + keyCounter + ", expecting '" + castedExpKey.toString() + "'");
}
keyCounter++;
}
for (Object castedExpKey : castedKeysMap.keySet()) {
String compareMessage = "Checking LinkedHashMap Entry for Key '" + castedExpKey.toString() + "' ";
if (!actualMap.containsKey(castedExpKey)) {
AssertionUtils.actionFail(compareMessage + "- Key not present in LinkedHashMap");
continue;
}
Object expectedObj = castedKeysMap.get(castedExpKey);
Object actualObj = actualMap.get(castedExpKey);
if (expectedObj==null) {
AssertionUtils.jettAssertNull(compareMessage + "expected object is null, check if actual object is null.",actualObj);
} else if (actualObj==null) {
AssertionUtils.jettAssertNull(compareMessage + "actual is object is null, checking if expected object is null.",expectedObj);
} else {
DataTypeEnum type;
type = ObjectUtil.resolveType(actualObj);
switch(type) {
case JAVA_DOT_LANG_OBJECT:
case STRING:
Object castedExpectedObj = Reflect.getWrappedValue(actualObj.getClass(), expectedObj);
AssertionUtils.jettAssertEquals(compareMessage, castedExpectedObj, actualObj);
break;
default:
AssertionUtils.actionPass(compareMessage + "- Key Present - Checking values:");
IAssertion assertionProcessor = AssertionProcessorFactory.getAssertionProcessor(type);
assertionProcessor.execute(compareMessage, expectedObj, actualObj, null);
break;
}
}
}
}
}