def compareSymbol(settings, testName, name, newSym, expSym, newSymbols, expSymbols, errors): newVal = newSym.value newLiNo = newSym.liNo expVal = expSym.value expLiNo = expSym.liNo if name in symMustChangeBetweenHands and not newSymbolsFinalPrevHand is None and newVal == newSymbolsFinalPrevHand.getValue(name): createErrorEntry(testName, errors.symbols, msg="Symbol '" + name + "' should change value between hands but does not", nLiNo=newLiNo) return True if name in symMustBeSameDuringHand and not newSymbolsPrevDumpThisHand is None and newVal != newSymbolsPrevDumpThisHand.getValue(name): createErrorEntry(testName, errors.symbols, msg="Symbol '" + name + "' should not change value during hand but does", nLiNo=newLiNo) return True #fixme: what if we dumped multiple times in one heardbeat (e.g. prefold call and alli call, or wait and alli, or 2 alli because of illegal action)??? if name in symMustChangeEachHeardbeat and not newSymbolsPrevDumpThisHand is None and newVal == newSymbolsPrevDumpThisHand.getValue(name): createErrorEntry(testName, errors.symbols, msg="Symbol '" + name + "' should change each heartbeat but does not", nLiNo=newLiNo) return True if name in symMustChangePerBetround and not newSymbolsPrevBetround is None and newVal == newSymbolsPrevBetround.getValue(name): createErrorEntry(testName, errors.symbols, msg="Symbol '" + name + "' should change each betround but does not", nLiNo=newLiNo) return True if name in symMustBeSameDuringBetround and not newSymbolsPrevDumpThisHand is None and newSymbols.getValue('betround') == newSymbolsPrevDumpThisHand.getValue('betround') and newVal != newSymbolsPrevDumpThisHand.getValue(name): createErrorEntry(testName, errors.symbols, msg="Symbol '" + name + "' should not change value during betround but does", nLiNo=newLiNo) return True for prefix in symDontRequireSameValuePrefixes: if name.startswith(prefix): return True #convert card values between different OH versions if needed for p in cardSymbolPrefix: if name.startswith(p): newVal = convertCardValue(settings, name, newVal, newSymbols) #return newVal == expVal return floatEq(newVal, expVal)
def compareSymbols(settings, testName, newSymbols, expSymbols, errors): #fixme: bad idea? config value to allow change? for sure since symbols can be added or removed to OH if len(newSymbols.keys()) != len(expSymbols.keys()): createErrorEntry(testName, errors.symbols, msg='Number of symbols does not match', nLiNo=newSymbols.liNo, eLiNo=expSymbols.liNo) #do some extra eval on betround since we rely on it! if not newSymbolsPrevDumpThisHand is None: if newSymbols.getValue('betround') == newSymbolsPrevDumpThisHand.getValue('betround') and not isSameBoard(newSymbols, newSymbolsPrevDumpThisHand): createErrorEntry(testName, errors.symbols, msg='Board cards changed during betround', nLiNo=newSymbols.liNo) elif newSymbols.getValue('betround') != newSymbolsPrevDumpThisHand.getValue('betround') and isSameBoard(newSymbols, newSymbolsPrevDumpThisHand): createErrorEntry(testName, errors.symbols, msg='Board cards the same but is new betround', nLiNo=newSymbols.liNo) for n in newSymbols.keys(): #to compare with earlier OH versions with different symbols #and some symbols are new or do no longer exist ignoreSym = False for p in settings.ignoreSymbolsPrefix: if n.startswith(p): ignoreSym = True break if ignoreSym or n in settings.ignoreSymbolsExact: continue newNV = newSymbols.get(n) expNV = expSymbols.get(n) newVal = newNV.value newLiNo = newNV.liNo expVal = None expLiNo = expSymbols.liNo if not expNV is None: expVal = expNV.value expLiNo = expNV.liNo if not compareSymbol(settings, testName, n, newNV, expNV, newSymbols, expSymbols, errors): createErrorEntry(testName, errors.symbols, msg="Symbol '" + n + "' does not match: '" + str(newVal) + "' != '" + str(expVal) + "'", nLiNo=newLiNo, eLiNo=expLiNo) else: createErrorEntry(testName, errors.symbols, msg="Symbol '" + n + "' missing in expected output log", nLiNo=newLiNo, eLiNo=expSymbols.liNo)
def compareStates(testName, newState, expState, errors): if len(newState.keys()) != len(expState.keys()): createErrorEntry(testName, errors.state, msg='Number of entries in state does not match', nLiNo=newState.liNo, eLiNo=expState.liNo) for n in newState.keys(): newNV = newState.get(n) expNV = expState.get(n) newVal = newNV.value newLiNo = newNV.liNo expVal = None expLiNo = None if not expNV is None: expVal = expNV.value expLiNo = expNV.liNo if expVal != newVal: createErrorEntry(testName, errors.state, msg="State entry '" + n + "' does not match: '" + str(newVal) + "' != '" + str(expVal) + "'", nLiNo=newLiNo, eLiNo=expLiNo) else: createErrorEntry(testName, errors.state, msg="State entry '" + n + "' missing in expected output log", nLiNo=newLiNo, eLiNo=expState.liNo)
def handleSymbolsAndStates(settings, testName, newLineEntries, expLineEntries, errors): newSymbolsPrevDumpThisHand = None newSymbolsPrevBetround = None curBetround = -1 newSymStatePairList = parseNamedValues(testName, newLineEntries, False, errors) expSymStatePairList = parseNamedValues(testName, expLineEntries, True, errors) #print("DEBUG: len(newLineEntries)=%i len(expLineEntries)=%i len(newSymStatePairList)=%i len(expSymStatePairList)=%i" % (len(newLineEntries), len(expLineEntries), len(newSymStatePairList), len(expSymStatePairList))) castSymbolValuesToFloat(newSymStatePairList, expSymStatePairList) newAllInCaseSymPairList = hashAndFindAllInStates(newSymStatePairList) expAllInCaseSymPairList = hashAndFindAllInStates(expSymStatePairList) #fixme: the first one is empty!!!! #if len(newAllInCaseSymPairList) == 0: # createErrorEntry(testName, errors.fatal, msg='No all-in messages in this test case', nLiNo=newLineEntries[0].liNo, eLiNo=expLineEntries[0].liNo) # return if len(newAllInCaseSymPairList) != len(expAllInCaseSymPairList): if len(newLineEntries) > 0 and len(expLineEntries) > 0: createErrorEntry(testName, errors.fatal, msg='Number of all-in messages in this test case do not match', nLiNo=newLineEntries[0].liNo, eLiNo=expLineEntries[0].liNo) elif len(newLineEntries) > 0: createErrorEntry(testName, errors.fatal, msg='Number of all-in messages in this test case do not match', nLiNo=newLineEntries[0].liNo) else: createErrorEntry(testName, errors.fatal, msg='Number of all-in messages in this test case do not match') for i in range(0, min(len(newAllInCaseSymPairList), len(expAllInCaseSymPairList))): newSymbols = newAllInCaseSymPairList[i][0] expSymbols = expAllInCaseSymPairList[i][0] newState = newAllInCaseSymPairList[i][1] expState = expAllInCaseSymPairList[i][1] compareStates(testName, newState, expState, errors) compareSymbols(settings, testName, newSymbols, expSymbols, errors) newSymbolsPrevDumpThisHand = newSymbols if curBetround + 0.1 < newSymbols.getValue('betround'): newSymbolsPrevBetround = newSymbols curBetround = newSymbols.getValue('betround') newSymbolsFinalPrevHand = newSymbolsPrevDumpThisHand
def parseNamedValues(testName, lineEntries, isExpectedLog, errors): inParseSymbolMode = False inParseStateMode = False curSymbolContainer = None curContainer = None newLiNo = None expLiNo = None containerPairList = [] inExpStr = '' if isExpectedLog: inExpStr = '(in expected log!): ' for e in lineEntries: #ensure we log line numbers for the correct log file if not isExpectedLog: newLiNo = e.liNo expLiNo = None else: newLiNo = -1 expLiNo = e.liNo mSym = beginSymbolDumpRe.match(e.line) mState = beginStateDumpRe.match(e.line) if mSym or mState: if inParseSymbolMode or inParseStateMode: createErrorEntry(testName, errors.fatal, msg=inExpStr + 'Next Dump seems to start inside another dump', nLiNo=newLiNo, eLiNo=expLiNo) if mSym: inParseSymbolMode = True inParseStateMode = False curContainer = NamedValueContainer(int(mSym.group(1)), bool(mSym.group(2)), e.liNo) elif mState: inParseSymbolMode = False inParseStateMode = True curContainer = NamedValueContainer(int(mState.group(1)), bool(mState.group(2)), e.liNo) continue if endSymbolDumpRe.match(e.line): if not inParseSymbolMode or inParseStateMode: createErrorEntry(testName, errors.fatal, msg=inExpStr + 'Unexpected Symbol Dump end marker', nLiNo=newLiNo, eLiNo=expLiNo) #we add it to result if we have state too inParseSymbolMode = False inParseStateMode = False curSymbolContainer = curContainer curContainer = None continue if endStateDumpRe.match(e.line): if inParseSymbolMode or not inParseStateMode: createErrorEntry(testName, errors.fatal, msg=inExpStr + 'Unexpected State Dump end marker', nLiNo=newLiNo, eLiNo=expLiNo) if curSymbolContainer is None: createErrorEntry(testName, errors.fatal, msg=inExpStr + "Fatal: State without previous matching Symbols", nLiNo=newLiNo, eLiNo=expLiNo) curSymbolContainer = NamedValueContainer(curContainer.inHandMsgNum, curContainer.isAllInMsg, curContainer.liNo) if curSymbolContainer.isAllInMsg != curContainer.isAllInMsg: createErrorEntry(testName, errors.fatal, msg=inExpStr + "Fatal: 'isAllInMsg' of state and symbols not matching", nLiNo=newLiNo, eLiNo=expLiNo) inParseSymbolMode = False inParseStateMode = False containerPairList.append((curSymbolContainer, curContainer)) curSymbolContainer = None curContainer = None continue if inParseSymbolMode or inParseStateMode: m = namedValueLineRe.match(e.line) if m: curContainer.add(m.group(1), m.group(2), e.liNo) else: createErrorEntry(testName, errors.fatal, msg=inExpStr + 'In Dump and cannot parse line as named value', nLine=e.line, nLiNo=newLiNo, eLiNo=expLiNo) if inParseSymbolMode or inParseStateMode: createErrorEntry(testName, errors.fatal, msg=inExpStr + 'Dump seems to have no end inside test case', nLiNo=newLiNo, eLiNo=expLiNo) return containerPairList