/* * #%~ * VDM Code Generator * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.codegen.tests.exec.util; import java.io.File; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.codegen.runtime.Record; import org.overture.codegen.runtime.Token; import org.overture.codegen.runtime.Tuple; import org.overture.codegen.runtime.VDMMap; import org.overture.codegen.runtime.VDMSeq; import org.overture.codegen.runtime.VDMSet; import org.overture.ct.ctruntime.utils.TraceTest; import org.overture.interpreter.traces.Verdict; import org.overture.interpreter.values.BooleanValue; import org.overture.interpreter.values.CharacterValue; import org.overture.interpreter.values.FieldMap; import org.overture.interpreter.values.FieldValue; import org.overture.interpreter.values.InvariantValue; import org.overture.interpreter.values.MapValue; import org.overture.interpreter.values.NameValuePairMap; import org.overture.interpreter.values.NilValue; import org.overture.interpreter.values.NumericValue; import org.overture.interpreter.values.ObjectValue; import org.overture.interpreter.values.QuoteValue; import org.overture.interpreter.values.RecordValue; import org.overture.interpreter.values.SeqValue; import org.overture.interpreter.values.SetValue; import org.overture.interpreter.values.TokenValue; import org.overture.interpreter.values.TupleValue; import org.overture.interpreter.values.UpdatableValue; import org.overture.interpreter.values.Value; public class ComparisonIR { public ComparisonIR(File testInputFile) { if (testInputFile == null) { throw new IllegalArgumentException("Test file cannot be null"); } } public boolean compare(Object cgResult, Object vdmResult) { // If the VDM result is a String then it must be an error message if (vdmResult instanceof String) { String vdmError = vdmResult.toString(); String cgError = cgResult.toString(); return vdmError.toLowerCase().contains("error") && vdmError.contains(cgError); } if (!(vdmResult instanceof Value)) { if (vdmResult instanceof List && cgResult instanceof List) { @SuppressWarnings("rawtypes") List vdmList = (List) vdmResult; @SuppressWarnings("rawtypes") List cgList = (List) cgResult; if (vdmList.size() != cgList.size()) { return false; } for (int i = 0; i < vdmList.size(); i++) { Object vdmElem = vdmList.get(i); Object cgElem = cgList.get(i); if (vdmElem instanceof TraceTest && cgElem instanceof org.overture.codegen.runtime.traces.TraceTest) { TraceTest vdmTest = (TraceTest) vdmElem; org.overture.codegen.runtime.traces.TraceTest cgTest = (org.overture.codegen.runtime.traces.TraceTest) cgElem; if (vdmTest.getVerdict().toString().equals(cgTest.getVerdict().toString())) { if (!(vdmTest.getNo().equals(cgTest.getNo()) && vdmTest.getTest().equals(cgTest.getTest()))) { return false; } if (vdmTest.getVerdict() == Verdict.PASSED) { if (!vdmTest.getResult().equals(cgTest.getResult())) { return false; } } } else { return false; } } else { return false; } } return true; } else { return false; } } Value vdmValue = (Value) vdmResult; while (vdmValue instanceof UpdatableValue) { UpdatableValue upValue = (UpdatableValue) vdmValue; vdmValue = upValue.getConstant(); } while (vdmValue instanceof InvariantValue) { vdmValue = vdmValue.deref(); } if (vdmValue instanceof BooleanValue) { return handleBoolean(cgResult, vdmValue); } else if (vdmValue instanceof CharacterValue) { return handleCharacter(cgResult, vdmValue); } else if (vdmValue instanceof MapValue) { return handleMap(cgResult, vdmValue); } else if (vdmValue instanceof QuoteValue) { return handleQuote(cgResult, vdmValue); } else if (vdmValue instanceof NumericValue) { return handleNumber(cgResult, vdmValue); } else if (vdmValue instanceof SeqValue) { if (cgResult instanceof String) { return handleString(cgResult, vdmValue); } else { return handleSeq(cgResult, vdmValue); } } else if (vdmValue instanceof SetValue) { return handleSet(cgResult, vdmValue); } else if (vdmValue instanceof TupleValue) { return handleTuple(cgResult, vdmValue); } else if (vdmValue instanceof TokenValue) { return handleToken(cgResult, vdmValue); } else if (vdmValue instanceof NilValue) { return cgResult == null; } else if (vdmValue instanceof ObjectValue) { return handleObject(cgResult, vdmValue); } else if (vdmValue instanceof RecordValue) { return handleRecord(cgResult, vdmValue); } return false; } private boolean handleRecord(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Record)) { return false; } RecordValue vdmRecord = (RecordValue) vdmValue; Record cgRecord = (Record) cgValue; if (!cgRecord.getClass().getName().endsWith(vdmRecord.type.getName().getName())) { return false; } Field[] cgRecFields = cgRecord.getClass().getFields(); FieldMap vdmRecFields = vdmRecord.fieldmap; for (int i = 0; i < vdmRecFields.size(); i++) { FieldValue vdmField = vdmRecFields.get(i); Field cgField = cgRecFields[i]; try { if (!cgField.getName().equals(vdmField.name)) { return false; } if (!compare(cgField.get(cgRecord), vdmField.value)) { return false; } } catch (Exception e) { e.printStackTrace(); return false; } } return true; } private boolean handleObject(Object cgValue, Value vdmValue) { ObjectValue vdmObject = (ObjectValue) vdmValue; Field[] fields = cgValue.getClass().getFields(); NameValuePairMap memberValues = vdmObject.getMemberValues(); Set<ILexNameToken> keySet = memberValues.keySet(); for (Field field : fields) { boolean foundMatchingField = false; for (ILexNameToken tok : keySet) { if (field.getName().equals(tok.getName())) { Value vdmFieldValue = memberValues.get(tok); if (vdmFieldValue != null) { try { Object cgFieldValue = field.get(cgValue); if (compare(cgFieldValue, vdmFieldValue)) { foundMatchingField = true; break; } } catch (Exception e) { e.printStackTrace(); return false; } } } } if (!foundMatchingField) { return false; } } return true; } private boolean handleQuote(Object cgValue, Value vdmValue) { if (cgValue == null) { return false; } // For example, the replacement constructs <A> from <AQuote> return cgValue.toString().replace("Quote>", ">").equals(vdmValue.toString()); } private boolean handleToken(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Token)) { return false; } Token cgToken = (Token) cgValue; TokenValue vdmToken = (TokenValue) vdmValue; try { Field f = vdmToken.getClass().getDeclaredField("value"); f.setAccessible(true); Value value = (Value) f.get(vdmToken); return compare(cgToken.getValue(), value); } catch (Exception e) { e.printStackTrace(); return false; } } private static boolean handleCharacter(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Character)) { return false; } Character cgChar = (Character) cgValue; CharacterValue vdmChar = (CharacterValue) vdmValue; return cgChar != null && cgChar == vdmChar.unicode; } private static boolean handleNumber(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Number)) { return false; } Number number = (Number) cgValue; NumericValue vdmNumeric = (NumericValue) vdmValue; return number.doubleValue() == vdmNumeric.value; } private boolean handleSeq(Object cgValue, Value vdmValue) { if (!(cgValue instanceof VDMSeq)) { return false; } VDMSeq cgSeq = (VDMSeq) cgValue; SeqValue vdmSeq = (SeqValue) vdmValue; if (cgSeq.size() != vdmSeq.values.size()) { return false; } for (int i = 0; i < cgSeq.size(); i++) { Object cgElement = cgSeq.get(i); Value vdmElement = vdmSeq.values.get(i); if (!compare(cgElement, vdmElement)) { return false; } } return true; } private boolean handleSet(Object cgValue, Value vdmValue) { if (!(cgValue instanceof VDMSet)) { return false; } VDMSet cgSet = (VDMSet) cgValue; SetValue vdmSet = (SetValue) vdmValue; if (cgSet.size() != vdmSet.values.size()) { return false; } @SuppressWarnings("unchecked") List<Object> cgValuesList = new LinkedList<Object>(cgSet); List<Value> vdmValuesList = new LinkedList<Value>(vdmSet.values); for (int i = 0; i < cgValuesList.size(); i++) { Object cgElement = cgValuesList.get(i); boolean match = false; for (int k = 0; k < vdmValuesList.size(); k++) { Value vdmElement = vdmValuesList.get(k); if (compare(cgElement, vdmElement)) { match = true; break; } } if (!match) { return false; } } return true; } private boolean handleTuple(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Tuple)) { return false; } Tuple javaTuple = (Tuple) cgValue; TupleValue vdmTuple = (TupleValue) vdmValue; if (javaTuple.size() != vdmTuple.values.size()) { return false; } for (int i = 0; i < javaTuple.size(); i++) { if (!compare(javaTuple.get(i), vdmTuple.values.get(i))) { return false; } } return true; } private boolean handleString(Object cgValue, Value vdmValue) { if (!(cgValue instanceof String)) { return false; } String cgString = (String) cgValue; SeqValue vdmSeq = (SeqValue) vdmValue; if (cgString.length() != vdmSeq.values.size()) { return false; } for (int i = 0; i < cgString.length(); i++) { if (!compare(cgString.charAt(i), vdmSeq.values.get(i))) { return false; } } return true; } private boolean handleMap(Object cgValue, Value vdmValue) { if (!(cgValue instanceof VDMMap)) { return false; } VDMMap cgMap = (VDMMap) cgValue; MapValue vdmMap = (MapValue) vdmValue; if (cgMap.size() != vdmMap.values.size()) { return false; } for (Object cgKey : cgMap.keySet()) { boolean match = false; for (Value vdmKey : vdmMap.values.keySet()) { if (compare(cgKey, vdmKey)) { Object cgVal = cgMap.get(cgKey); Value vdmVal = vdmMap.values.get(vdmKey); if (compare(cgVal, vdmVal)) { match = true; break; } } } if (!match) { return false; } } return true; } private boolean handleBoolean(Object cgValue, Value vdmValue) { if (!(cgValue instanceof Boolean)) { return false; } Boolean cgBool = (Boolean) cgValue; BooleanValue vdmBool = (BooleanValue) vdmValue; return cgBool != null && cgBool == vdmBool.value; } }