diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java index cf1446ee155e..90f1e605e6b5 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java @@ -799,7 +799,9 @@ public enum DiagnosticErrorCode implements DiagnosticCode { EMPTY_REGEXP_STRING_DISALLOWED( "BCS4044", "empty.regexp.string.disallowed"), UNSUPPORTED_EMPTY_CHARACTER_CLASS( - "BCS4045", "unsupported.empty.character.class") + "BCS4045", "unsupported.empty.character.class"), + + INVALID_BINDING_PATTERN_IN_ON_FAIL("BCS4046", "invalid.binding.pattern.in.on.fail") ; private String diagnosticId; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ASTBuilderUtil.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ASTBuilderUtil.java index 977f838261e5..1da3556f467a 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ASTBuilderUtil.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ASTBuilderUtil.java @@ -53,6 +53,7 @@ import org.wso2.ballerinalang.compiler.tree.BLangService; import org.wso2.ballerinalang.compiler.tree.BLangSimpleVariable; import org.wso2.ballerinalang.compiler.tree.BLangTupleVariable; +import org.wso2.ballerinalang.compiler.tree.BLangVariable; import org.wso2.ballerinalang.compiler.tree.bindingpatterns.BLangBindingPattern; import org.wso2.ballerinalang.compiler.tree.bindingpatterns.BLangCaptureBindingPattern; import org.wso2.ballerinalang.compiler.tree.clauses.BLangMatchClause; @@ -552,6 +553,21 @@ static BLangRecordVariableDef createRecordVariableDef(Location pos, BLangRecordV return variableDef; } + static BLangErrorVariable createErrorVariable(Location pos, BType type, BLangExpression expr, + BLangSimpleVariable message, BLangVariable cause, + BLangSimpleVariable restDetail, + List detail) { + final BLangErrorVariable errVariable = (BLangErrorVariable) TreeBuilder.createErrorVariableNode(); + errVariable.pos = pos; + errVariable.setBType(type); + errVariable.expr = expr; + errVariable.message = message; + errVariable.cause = cause; + errVariable.restDetail = restDetail; + errVariable.detail = detail; + return errVariable; + } + static BLangErrorVariableDef createErrorVariableDef(Location pos, BLangErrorVariable variable) { final BLangErrorVariableDef variableDef = (BLangErrorVariableDef) TreeBuilder.createErrorVariableDefinitionNode(); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java index c9f8ecc5ffd4..389691721131 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java @@ -5157,18 +5157,8 @@ private BLangFail createOnFailInvocation(BLangOnFailClause onFailClause, BLangFa onFailBody.stmts.addAll(onFailClause.body.stmts); env.scope.entries.putAll(onFailClause.body.scope.entries); onFailBody.failureBreakMode = onFailClause.body.failureBreakMode; - VariableDefinitionNode onFailVarDefNode = onFailClause.variableDefinitionNode; - if (onFailVarDefNode != null) { - BVarSymbol onFailErrorVariableSymbol = - ((BLangSimpleVariableDef) onFailVarDefNode).var.symbol; - BLangSimpleVariable errorVar = ASTBuilderUtil.createVariable(onFailErrorVariableSymbol.pos, - onFailErrorVariableSymbol.name.value, onFailErrorVariableSymbol.type, rewrite(fail.expr, env), - onFailErrorVariableSymbol); - BLangSimpleVariableDef errorVarDef = ASTBuilderUtil.createVariableDef(onFailClause.pos, errorVar); - env.scope.define(onFailErrorVariableSymbol.name, onFailErrorVariableSymbol); - onFailBody.stmts.add(0, errorVarDef); - } + handleOnFailErrorVarDefNode(onFailClause.variableDefinitionNode, onFailBody, fail); if (onFailClause.isInternal && fail.exprStmt != null) { if (fail.exprStmt instanceof BLangPanic) { @@ -5187,6 +5177,38 @@ onFailErrorVariableSymbol.name.value, onFailErrorVariableSymbol.type, rewrite(fa return fail; } + private void handleOnFailErrorVarDefNode(VariableDefinitionNode onFailVarDefNode, BLangBlockStmt onFailBody, + BLangFail fail) { + if (onFailVarDefNode != null) { + BLangStatement stmt; + BLangVariable variableNode = (BLangVariable) onFailVarDefNode.getVariable(); + if (variableNode.getKind() == NodeKind.ERROR_VARIABLE) { + stmt = handleErrorBPInOnFail((BLangErrorVariable) variableNode, fail); + } else { + stmt = handleCaptureBPInOnFail((BLangSimpleVariable) variableNode, fail); + } + onFailBody.stmts.add(0, stmt); + } + } + + private BLangStatement handleErrorBPInOnFail (BLangErrorVariable varNode, BLangFail fail) { + BLangErrorVariable errorVar = ASTBuilderUtil.createErrorVariable(varNode.pos, + varNode.getBType(), rewrite(fail.expr, env), varNode.message, varNode.cause, varNode.restDetail, + varNode.detail); + BLangErrorVariableDef errorVarDef = ASTBuilderUtil.createErrorVariableDef(onFailClause.pos, errorVar); + return rewrite(errorVarDef, env); + } + + private BLangStatement handleCaptureBPInOnFail(BLangSimpleVariable varNode, BLangFail fail) { + BVarSymbol onFailErrorVariableSymbol = varNode.symbol; + BLangSimpleVariable errorVar = ASTBuilderUtil.createVariable(onFailErrorVariableSymbol.pos, + onFailErrorVariableSymbol.name.value, onFailErrorVariableSymbol.type, rewrite(fail.expr, env), + onFailErrorVariableSymbol); + BLangSimpleVariableDef errorVarDef = ASTBuilderUtil.createVariableDef(onFailClause.pos, errorVar); + env.scope.define(onFailErrorVariableSymbol.name, onFailErrorVariableSymbol); + return errorVarDef; + } + private BLangBlockStmt rewriteNestedOnFail(BLangOnFailClause onFailClause, BLangFail fail) { BLangOnFailClause currentOnFail = this.onFailClause; @@ -5195,18 +5217,8 @@ private BLangBlockStmt rewriteNestedOnFail(BLangOnFailClause onFailClause, BLang onFailBody.scope = onFailClause.body.scope; onFailBody.mapSymbol = onFailClause.body.mapSymbol; onFailBody.failureBreakMode = onFailClause.body.failureBreakMode; - VariableDefinitionNode onFailVarDefNode = onFailClause.variableDefinitionNode; - if (onFailVarDefNode != null) { - BVarSymbol onFailErrorVariableSymbol = - ((BLangSimpleVariableDef) onFailVarDefNode).var.symbol; - BLangSimpleVariable errorVar = ASTBuilderUtil.createVariable(onFailErrorVariableSymbol.pos, - onFailErrorVariableSymbol.name.value, onFailErrorVariableSymbol.type, rewrite(fail.expr, env), - onFailErrorVariableSymbol); - BLangSimpleVariableDef errorVarDef = ASTBuilderUtil.createVariableDef(onFailClause.pos, errorVar); - onFailBody.scope.define(onFailErrorVariableSymbol.name, onFailErrorVariableSymbol); - onFailBody.stmts.add(0, errorVarDef); - } + handleOnFailErrorVarDefNode(onFailClause.variableDefinitionNode, onFailBody, fail); int currentOnFailIndex = this.enclosingOnFailClause.indexOf(this.onFailClause); int enclosingOnFailIndex = currentOnFailIndex <= 0 ? this.enclosingOnFailClause.size() - 1 diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java index 1c8e9c34b0c1..a5fbfb23ba0c 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangNodeBuilder.java @@ -3921,15 +3921,13 @@ public BLangNode transform(OnFailClauseNode onFailClauseNode) { BLangOnFailClause onFailClause = (BLangOnFailClause) TreeBuilder.createOnFailClauseNode(); onFailClause.pos = pos; onFailClauseNode.typedBindingPattern().ifPresent(typedBindingPatternNode -> { - if (typedBindingPatternNode.bindingPattern().kind() == SyntaxKind.CAPTURE_BINDING_PATTERN) { - VariableDefinitionNode variableDefinitionNode = - createBLangVarDef(getPosition(typedBindingPatternNode), typedBindingPatternNode, - Optional.empty(), Optional.empty()); - onFailClause.isDeclaredWithVar = - typedBindingPatternNode.typeDescriptor().kind() == SyntaxKind.VAR_TYPE_DESC; - markVariableWithFlag((BLangVariable) variableDefinitionNode.getVariable(), Flag.FINAL); - onFailClause.variableDefinitionNode = variableDefinitionNode; - } + VariableDefinitionNode variableDefinitionNode = + createBLangVarDef(getPosition(typedBindingPatternNode), typedBindingPatternNode, + Optional.empty(), Optional.empty()); + onFailClause.isDeclaredWithVar = + typedBindingPatternNode.typeDescriptor().kind() == SyntaxKind.VAR_TYPE_DESC; + markVariableWithFlag((BLangVariable) variableDefinitionNode.getVariable(), Flag.FINAL); + onFailClause.variableDefinitionNode = variableDefinitionNode; }); BLangBlockStmt blockNode = (BLangBlockStmt) transform(onFailClauseNode.blockStatement()); blockNode.pos = pos; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java index 4b2d41e23a0a..c9ef485b71fd 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/CodeAnalyzer.java @@ -579,7 +579,6 @@ public void visit(BLangTransaction transactionNode, AnalyzerData data) { boolean onFailExists = transactionNode.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } analyzeNode(transactionNode.transactionBody, data); @@ -654,7 +653,6 @@ public void visit(BLangRetry retryNode, AnalyzerData data) { boolean onFailExists = retryNode.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } visitNode(retryNode.retrySpec, data); @@ -771,7 +769,6 @@ public void visit(BLangMatchStatement matchStatement, AnalyzerData data) { boolean onFailExists = matchStatement.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } List matchClauses = matchStatement.matchClauses; @@ -1471,7 +1468,6 @@ public void visit(BLangForeach foreach, AnalyzerData data) { boolean onFailExists = foreach.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } data.loopCount++; @@ -1492,7 +1488,6 @@ public void visit(BLangWhile whileNode, AnalyzerData data) { boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } data.loopCount++; @@ -1511,7 +1506,6 @@ public void visit(BLangDo doNode, AnalyzerData data) { boolean onFailExists = doNode.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } analyzeNode(doNode.body, data); @@ -1529,29 +1523,20 @@ public void visit(BLangFail failNode, AnalyzerData data) { return; } typeChecker.checkExpr(failNode.expr, data.env); - if (!data.errorTypes.empty()) { - data.errorTypes.peek().add(getErrorTypes(failNode.expr.getBType())); - } if (!data.failureHandled) { BType exprType = data.env.enclInvokable.getReturnTypeNode().getBType(); data.returnTypes.peek().add(exprType); - if (!types.isAssignable(getErrorTypes(failNode.expr.getBType()), exprType)) { + if (!types.isAssignable(types.getErrorTypes(failNode.expr.getBType()), exprType)) { dlog.error(failNode.pos, DiagnosticErrorCode.FAIL_EXPR_NO_MATCHING_ERROR_RETURN_IN_ENCL_INVOKABLE); } } } - private BLangBlockStmt.FailureBreakMode getPossibleBreakMode(boolean possibleFailurePresent) { - return possibleFailurePresent ? BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK - : BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE; - } - @Override public void visit(BLangLock lockNode, AnalyzerData data) { boolean onFailExists = lockNode.onFailClause != null; boolean failureHandled = data.failureHandled; if (onFailExists) { - data.errorTypes.push(new LinkedHashSet<>()); data.failureHandled = true; } boolean previousWithinLockBlock = data.withinLockBlock; @@ -3188,7 +3173,7 @@ public void visit(BLangCheckedExpr checkedExpr, AnalyzerData data) { return; } - BType exprErrorTypes = getErrorTypes(checkedExpr.expr.getBType()); + BType exprErrorTypes = types.getErrorTypes(checkedExpr.expr.getBType()); BType initMethodReturnType = initializerFunc.type.retType; if (!types.isAssignable(exprErrorTypes, initMethodReturnType)) { dlog.error(checkedExpr.pos, DiagnosticErrorCode @@ -3205,7 +3190,7 @@ public void visit(BLangCheckedExpr checkedExpr, AnalyzerData data) { BType exprType = enclInvokable.getReturnTypeNode().getBType(); BType checkedExprType = checkedExpr.expr.getBType(); - BType errorType = getErrorTypes(checkedExprType); + BType errorType = types.getErrorTypes(checkedExprType); if (errorType == symTable.semanticError) { return; @@ -3217,9 +3202,6 @@ public void visit(BLangCheckedExpr checkedExpr, AnalyzerData data) { dlog.error(checkedExpr.pos, DiagnosticErrorCode.CHECKED_EXPR_NO_MATCHING_ERROR_RETURN_IN_ENCL_INVOKABLE); } - if (!data.errorTypes.empty()) { - data.errorTypes.peek().add(getErrorTypes(checkedExpr.expr.getBType())); - } BType errorTypes; if (exprType.tag == TypeTags.UNION) { @@ -3350,15 +3332,11 @@ public void visit(BLangOnFailClause onFailClause, AnalyzerData data) { VariableDefinitionNode onFailVarDefNode = onFailClause.variableDefinitionNode; if (onFailVarDefNode != null) { - BLangVariable onFailVarNode = (BLangVariable) onFailVarDefNode.getVariable(); - for (BType errorType : data.errorTypes.peek()) { - if (!types.isAssignable(errorType, onFailVarNode.getBType())) { - dlog.error(onFailVarNode.pos, DiagnosticErrorCode.INCOMPATIBLE_ON_FAIL_ERROR_DEFINITION, errorType, - onFailVarNode.getBType()); - } + BLangNode onFailVarNode = (BLangNode) onFailClause.getVariableDefinitionNode().getVariable(); + if (onFailVarNode != null) { + analyzeNode(onFailVarNode, data); } } - data.errorTypes.pop(); analyzeNode(onFailClause.body, data); onFailClause.bodyContainsFail = data.failVisited; data.failVisited = currentFailVisited; @@ -3367,7 +3345,6 @@ public void visit(BLangOnFailClause onFailClause, AnalyzerData data) { private void analyseOnFailAndUpdateBreakMode(boolean onFailExists, BLangBlockStmt blockStmt, BLangOnFailClause onFailClause, AnalyzerData data) { if (onFailExists) { - blockStmt.failureBreakMode = getPossibleBreakMode(!data.errorTypes.peek().isEmpty()); analyzeOnFailClause(onFailClause, data); } } @@ -3863,40 +3840,6 @@ private void validateModuleInitFunction(BLangFunction funcNode) { types.validateErrorOrNilReturn(funcNode, DiagnosticErrorCode.MODULE_INIT_RETURN_SHOULD_BE_ERROR_OR_NIL); } - private BType getErrorTypes(BType bType) { - if (bType == null) { - return symTable.semanticError; - } - - BType errorType = symTable.semanticError; - - int tag = bType.tag; - if (tag == TypeTags.TYPEREFDESC) { - return getErrorTypes(Types.getReferredType(bType)); - } - if (tag == TypeTags.ERROR) { - errorType = bType; - } else if (tag == TypeTags.READONLY) { - errorType = symTable.errorType; - } else if (tag == TypeTags.UNION) { - LinkedHashSet errTypes = new LinkedHashSet<>(); - Set memTypes = ((BUnionType) bType).getMemberTypes(); - for (BType memType : memTypes) { - BType memErrType = getErrorTypes(memType); - - if (memErrType != symTable.semanticError) { - errTypes.add(memErrType); - } - } - - if (!errTypes.isEmpty()) { - errorType = errTypes.size() == 1 ? errTypes.iterator().next() : BUnionType.create(null, errTypes); - } - } - - return errorType; - } - /** * This class contains the state machines for a set of workers. */ @@ -4177,7 +4120,6 @@ public static class AnalyzerData { boolean withinQuery; Types.QueryConstructType queryConstructType; Stack> returnTypes = new Stack<>(); - Stack> errorTypes = new Stack<>(); DefaultValueState defaultValueState = DefaultValueState.NOT_IN_DEFAULT_VALUE; } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java index 35446de14f2c..addf2016626d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/DataflowAnalyzer.java @@ -2269,9 +2269,12 @@ public void visit(BLangRecordVariableDef bLangRecordVariableDef) { public void visit(BLangErrorVariable bLangErrorVariable) { analyzeNode(bLangErrorVariable.typeNode, env); populateUnusedVariableMapForNonSimpleBindingPatternVariables(this.unusedLocalVariables, bLangErrorVariable); - this.currDependentSymbolDeque.push(bLangErrorVariable.symbol); - analyzeNode(bLangErrorVariable.expr, env); - this.currDependentSymbolDeque.pop(); + // When we visit this path from on fail clause the symbol is null + if (bLangErrorVariable.symbol != null) { + this.currDependentSymbolDeque.push(bLangErrorVariable.symbol); + analyzeNode(bLangErrorVariable.expr, env); + this.currDependentSymbolDeque.pop(); + } } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SemanticAnalyzer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SemanticAnalyzer.java index 51c60c80e963..ba818e572b48 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SemanticAnalyzer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/SemanticAnalyzer.java @@ -2106,12 +2106,12 @@ void handleDeclaredVarInForeach(BLangVariable variable, BType rhsType, SymbolEnv break; case ERROR_VARIABLE: BLangErrorVariable errorVariable = (BLangErrorVariable) variable; + errorVariable.setBType(rhsType); if (TypeTags.ERROR != Types.getReferredType(rhsType).tag) { dlog.error(variable.pos, DiagnosticErrorCode.INVALID_TYPE_DEFINITION_FOR_ERROR_VAR, rhsType); recursivelyDefineVariables(errorVariable, blockEnv); return; } - errorVariable.setBType(rhsType); this.symbolEnter.validateErrorVariable(errorVariable, blockEnv); recursivelySetFinalFlag(errorVariable); break; @@ -2882,6 +2882,10 @@ public void visit(BLangMatchStatement matchStatement, AnalyzerData data) { if (matchClauses.size() == 0) { return; } + boolean onFailExists = matchStatement.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); + } analyzeNode(matchClauses.get(0), data); SymbolEnv matchClauseEnv = data.env; @@ -2894,7 +2898,7 @@ public void visit(BLangMatchStatement matchStatement, AnalyzerData data) { analyzeNode(currentMatchClause, data); } - if (matchStatement.onFailClause != null) { + if (onFailExists) { this.analyzeNode(matchStatement.onFailClause, data); } } @@ -3853,13 +3857,16 @@ public void visit(BLangForeach foreach, AnalyzerData data) { handleForeachDefinitionVariables(foreach.variableDefinitionNode, foreach.varType, foreach.isDeclaredWithVar, false, blockEnv); boolean prevBreakFound = data.breakFound; + boolean onFailExists = foreach.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); + } + // Analyze foreach node's statements. data.env = blockEnv; analyzeStmt(foreach.body, data); - if (foreach.onFailClause != null) { - this.analyzeNode(foreach.onFailClause, data); - } + updateBreakMode(onFailExists, foreach.body, foreach.onFailClause, data); data.notCompletedNormally = false; data.breakFound = prevBreakFound; } @@ -3869,28 +3876,71 @@ public void visit(BLangOnFailClause onFailClause, AnalyzerData data) { // Create a new block environment for the on-fail node. SymbolEnv onFailEnv = SymbolEnv.createBlockEnv(onFailClause.body, data.env); VariableDefinitionNode onFailVarDefNode = onFailClause.variableDefinitionNode; + Stack> onFailErrTypes = data.commonAnalyzerData.errorTypes; + if (onFailVarDefNode != null) { + BLangVariable variableNode = (BLangVariable) onFailVarDefNode.getVariable(); + if (variableNode.getKind() != NodeKind.VARIABLE && variableNode.getKind() != NodeKind.ERROR_VARIABLE) { + dlog.error(variableNode.pos, DiagnosticErrorCode.INVALID_BINDING_PATTERN_IN_ON_FAIL); + } + + BType failErrorType; + LinkedHashSet onFailErrType = onFailErrTypes.peek(); + boolean isVarTypeHardcoded = false; + if (onFailErrType.size() == 1) { + failErrorType = onFailErrType.iterator().next(); + } else if (onFailErrType.size() > 1) { + failErrorType = BUnionType.create(null, onFailErrType); + } else { + failErrorType = symTable.errorType; + isVarTypeHardcoded = true; + } + // Check on-fail node's variables and set types. - handleForeachDefinitionVariables(onFailVarDefNode, symTable.errorType, - onFailClause.isDeclaredWithVar, true, onFailEnv); + handleForeachDefinitionVariables(onFailVarDefNode, failErrorType, + onFailClause.isDeclaredWithVar, isVarTypeHardcoded, onFailEnv); BLangVariable onFailVarNode = (BLangVariable) onFailVarDefNode.getVariable(); - if (!types.isAssignable(onFailVarNode.getBType(), symTable.errorType)) { + + if (onFailVarNode.getBType() != null && !types.isAssignable(onFailVarNode.getBType(), symTable.errorType)) { dlog.error(onFailVarNode.pos, DiagnosticErrorCode.INVALID_TYPE_DEFINITION_FOR_ERROR_VAR, onFailVarNode.getBType()); } + + for (BType errorType : onFailErrTypes.peek()) { + if (onFailVarNode.getBType() != null && !types.isAssignable(errorType, onFailVarNode.getBType())) { + dlog.error(onFailVarNode.pos, DiagnosticErrorCode.INCOMPATIBLE_ON_FAIL_ERROR_DEFINITION, errorType, + onFailVarNode.getBType()); + } + } } + + onFailErrTypes.pop(); data.env = onFailEnv; analyzeStmt(onFailClause.body, data); } + private void updateBreakMode(boolean onFailExists, BLangBlockStmt blockStmt, BLangOnFailClause onFailClause, + AnalyzerData data) { + if (onFailExists) { + blockStmt.failureBreakMode = getPossibleBreakMode(!data.commonAnalyzerData.errorTypes.peek().isEmpty()); + this.analyzeNode(onFailClause, data); + } + } + + private BLangBlockStmt.FailureBreakMode getPossibleBreakMode(boolean possibleFailurePresent) { + return possibleFailurePresent ? BLangBlockStmt.FailureBreakMode.BREAK_TO_OUTER_BLOCK + : BLangBlockStmt.FailureBreakMode.NOT_BREAKABLE; + } + @Override public void visit(BLangWhile whileNode, AnalyzerData data) { SymbolEnv currentEnv = data.env; typeChecker.checkExpr(whileNode.expr, currentEnv, symTable.booleanType, data.prevEnvs, data.commonAnalyzerData); - if (whileNode.onFailClause != null) { - this.analyzeNode(whileNode.onFailClause, data); + boolean onFailExists = whileNode.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); } BType actualType = whileNode.expr.getBType(); @@ -3906,15 +3956,18 @@ public void visit(BLangWhile whileNode, AnalyzerData data) { ConditionResolver.checkConstCondition(types, symTable, whileNode.expr) == symTable.trueType && !data.breakFound; data.breakFound = prevBreakFound; + updateBreakMode(onFailExists, whileNode.body, whileNode.onFailClause, data); } @Override public void visit(BLangDo doNode, AnalyzerData data) { data.env = SymbolEnv.createTypeNarrowedEnv(doNode, data.env); - if (doNode.onFailClause != null) { - this.analyzeNode(doNode.onFailClause, data); + boolean onFailExists = doNode.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); } analyzeStmt(doNode.body, data); + updateBreakMode(onFailExists, doNode.body, doNode.onFailClause, data); } @Override @@ -3922,7 +3975,9 @@ public void visit(BLangFail failNode, AnalyzerData data) { BLangExpression errorExpression = failNode.expr; BType errorExpressionType = typeChecker.checkExpr(errorExpression, data.env, data.prevEnvs, data.commonAnalyzerData); - + if (!data.commonAnalyzerData.errorTypes.empty()) { + data.commonAnalyzerData.errorTypes.peek().add(types.getErrorTypes(failNode.expr.getBType())); + } if (errorExpressionType == symTable.semanticError || !types.isSubTypeOfBaseType(errorExpressionType, symTable.errorType.tag)) { dlog.error(errorExpression.pos, DiagnosticErrorCode.ERROR_TYPE_EXPECTED, errorExpressionType); @@ -3933,10 +3988,12 @@ public void visit(BLangFail failNode, AnalyzerData data) { @Override public void visit(BLangLock lockNode, AnalyzerData data) { data.env = SymbolEnv.createLockEnv(lockNode, data.env); - analyzeStmt(lockNode.body, data); - if (lockNode.onFailClause != null) { - this.analyzeNode(lockNode.onFailClause, data); + boolean onFailExists = lockNode.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); } + analyzeStmt(lockNode.body, data); + updateBreakMode(onFailExists, lockNode.body, lockNode.onFailClause, data); } @Override @@ -4145,11 +4202,12 @@ private void validateDefaultable(BLangRecordTypeNode recordTypeNode) { @Override public void visit(BLangTransaction transactionNode, AnalyzerData data) { data.env = SymbolEnv.createTransactionEnv(transactionNode, data.env); - - if (transactionNode.onFailClause != null) { - this.analyzeNode(transactionNode.onFailClause, data); + boolean onFailExists = transactionNode.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); } analyzeStmt(transactionNode.transactionBody, data); + updateBreakMode(onFailExists, transactionNode.transactionBody, transactionNode.onFailClause, data); } @Override @@ -4176,11 +4234,12 @@ public void visit(BLangRetry retryNode, AnalyzerData data) { retryNode.retrySpec.accept(this, data); } data.env = SymbolEnv.createRetryEnv(retryNode, data.env); - analyzeStmt(retryNode.retryBody, data); - - if (retryNode.onFailClause != null) { - this.analyzeNode(retryNode.onFailClause, data); + boolean onFailExists = retryNode.onFailClause != null; + if (onFailExists) { + data.commonAnalyzerData.errorTypes.push(new LinkedHashSet<>()); } + analyzeStmt(retryNode.retryBody, data); + updateBreakMode(onFailExists, retryNode.retryBody, retryNode.onFailClause, data); } @Override @@ -4392,7 +4451,8 @@ private void checkAnnotConstantExpression(BLangExpression expression) { } private void handleForeachDefinitionVariables(VariableDefinitionNode variableDefinitionNode, BType varType, - boolean isDeclaredWithVar, boolean isOnFailDef, SymbolEnv blockEnv) { + boolean isDeclaredWithVar, boolean isVarTypeHardcoded, + SymbolEnv blockEnv) { BLangVariable variableNode = (BLangVariable) variableDefinitionNode.getVariable(); // Check whether the foreach node's variables are declared with var. if (isDeclaredWithVar) { @@ -4401,13 +4461,15 @@ private void handleForeachDefinitionVariables(VariableDefinitionNode variableDef return; } // If the type node is available, we get the type from it. + // Then, if the `varType` was hardcoded as `symtable.errorType`, we swap them and check whether `typeNodeType` + // is assignable to `symtable.errorType` BType typeNodeType = symResolver.resolveTypeNode(variableNode.typeNode, blockEnv); - if (isOnFailDef) { + if (isVarTypeHardcoded) { BType sourceType = varType; varType = typeNodeType; typeNodeType = sourceType; } - // Then we need to check whether the RHS type is assignable to LHS type. + // Checking whether the RHS type is assignable to LHS type. if (types.isAssignable(varType, typeNodeType)) { // If assignable, we set types to the variables. handleDeclaredVarInForeach(variableNode, varType, blockEnv); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java index 59704de86c20..0137417d1cf8 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/TypeChecker.java @@ -6109,6 +6109,10 @@ protected void visitCheckAndCheckPanicExpr(BLangCheckedExpr checkedExpr, Analyze errorTypes.add(exprType); } + if (!data.commonAnalyzerData.errorTypes.empty()) { + data.commonAnalyzerData.errorTypes.peek().add(types.getErrorTypes(checkedExpr.expr.getBType())); + } + // This list will be used in the desugar phase checkedExpr.equivalentErrorTypeList = errorTypes; if (errorTypes.isEmpty()) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java index 252d342ee605..2b879767da06 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/semantics/analyzer/Types.java @@ -253,6 +253,40 @@ public boolean typeIncompatible(Location pos, BType actualType, BType expType) { return checkType(pos, actualType, expType, DiagnosticErrorCode.INCOMPATIBLE_TYPES) == symTable.semanticError; } + public BType getErrorTypes(BType bType) { + if (bType == null) { + return symTable.semanticError; + } + + BType errorType = symTable.semanticError; + + int tag = bType.tag; + if (tag == TypeTags.TYPEREFDESC) { + return getErrorTypes(Types.getReferredType(bType)); + } + if (tag == TypeTags.ERROR) { + errorType = bType; + } else if (tag == TypeTags.READONLY) { + errorType = symTable.errorType; + } else if (tag == TypeTags.UNION) { + LinkedHashSet errTypes = new LinkedHashSet<>(); + Set memTypes = ((BUnionType) bType).getMemberTypes(); + for (BType memType : memTypes) { + BType memErrType = getErrorTypes(memType); + + if (memErrType != symTable.semanticError) { + errTypes.add(memErrType); + } + } + + if (!errTypes.isEmpty()) { + errorType = errTypes.size() == 1 ? errTypes.iterator().next() : BUnionType.create(null, errTypes); + } + } + + return errorType; + } + public BType checkType(Location pos, BType actualType, BType expType, @@ -7137,6 +7171,8 @@ public static class CommonAnalyzerData { boolean breakToParallelQueryEnv = false; int letCount = 0; boolean nonErrorLoggingCheck = false; + + Stack> errorTypes = new Stack<>(); } /** diff --git a/compiler/ballerina-lang/src/main/resources/compiler.properties b/compiler/ballerina-lang/src/main/resources/compiler.properties index aff8578d678e..6dd00b8f0427 100644 --- a/compiler/ballerina-lang/src/main/resources/compiler.properties +++ b/compiler/ballerina-lang/src/main/resources/compiler.properties @@ -1967,3 +1967,6 @@ error.empty.regexp.string.disallowed=\ error.unsupported.empty.character.class=\ empty character class disallowed + +error.invalid.binding.pattern.in.on.fail=\ + invalid binding pattern in ''on fail'' clause: only a capture binding pattern or an error binding pattern is allowed diff --git a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachNegativeTests.java b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachNegativeTests.java index 27687a5ac812..038ecd41f297 100644 --- a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachNegativeTests.java +++ b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachNegativeTests.java @@ -104,6 +104,8 @@ public void testForeachSemanticsNegative() { "mismatch with member type count", 342, 13); BAssertUtil.validateError(compile, index++, "invalid list binding pattern; member variable count " + "mismatch with member type count", 346, 18); + BAssertUtil.validateError(compile, index++, "invalid error variable; expecting an error type " + + "but found '(SampleComplexError|SampleError)' in type definition", 374, 15); Assert.assertEquals(compile.getErrorCount(), index); } diff --git a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachOnFailTests.java b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachOnFailTests.java index 375d29f8cc34..348415426e06 100644 --- a/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachOnFailTests.java +++ b/langlib/langlib-test/src/test/java/org/ballerinalang/langlib/test/statements/foreach/ForeachOnFailTests.java @@ -25,6 +25,7 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -85,4 +86,36 @@ public void testNestedWhileStmtWithFail() { Assert.assertTrue(result instanceof BString); Assert.assertEquals(result.toString(), expected); } + + @Test(dataProvider = "onFailClauseWithErrorBPTestDataProvider") + public void testOnFailWithErrorBP(String funcName) { + BRunUtil.invoke(program, funcName); + } + + @DataProvider(name = "onFailClauseWithErrorBPTestDataProvider") + public Object[] onFailClauseWithErrorBPTestDataProvider() { + return new Object[]{ + "testSimpleOnFailWithErrorBP", + "testSimpleOnFailWithErrorBPWithVar", + "testOnFailWithErrorBPHavingUserDefinedTypeWithError", + "testOnFailWithErrorBPHavingUserDefinedTypeWithVar", + "testOnFailWithErrorBPHavingUserDefinedType", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4", + "testOnFailWithErrorBPHavingAnonDetailRecord", + "testOnFailWithErrorBPHavingAnonDetailRecordWithVar", + "testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType", + "testOnFailWithErrorBPWithErrorArgsHavingBP1", + "testOnFailWithErrorBPWithErrorArgsHavingBP2", + "testOnFailWithErrorBPWithErrorArgsHavingBP3", + "testOnFailWithErrorBPWithErrorArgsHavingBP4", + "testOnFailWithErrorBPWithErrorArgsHavingBP5", + "testNestedOnFailWithErrorBP", + "testNestedOnFailWithErrorBPWithErrorArgsHavingBP", + "testMultiLevelOnFailWithErrorBP", + "testMultiLevelOnFailWithoutErrorInOneLevel" + }; + } } diff --git a/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-on-fail.bal b/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-on-fail.bal index 604aa95c37f3..4dd0f1ffc8da 100644 --- a/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-on-fail.bal +++ b/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-on-fail.bal @@ -93,3 +93,412 @@ function testNestedForeachLoopBreak() returns string { } return result; } + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; + +function testSimpleOnFailWithErrorBP() { + foreach var i in data { + fail error("error!"); + } on fail error error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + foreach var i in data { + fail error("error!"); + } on fail var error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + foreach var i in data { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + foreach var i in data { + error errVar = error("error", code = 34); + fail errVar; + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); + assertEquality(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + foreach var i in data { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg; + foreach var i in data { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(causeMsg, "Database Error"); + assertEquality(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + foreach var i in data { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + foreach var i in data { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + foreach var i in data { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + foreach var i in data { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +int testErrorCodeNested = 0; +string testMessageNested = ""; + +function testNestedOnFailWithErrorBP() { + string testErrorReasonNested = ""; + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + foreach var j in data { + fail error SampleError("nested error!", code = 30, reason = "database error"); + } on fail var error(msg2, code = errCode2, reason = errReason2) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testErrorReason = errReason1; + testErrorReasonNested = errReason2; + testMessage = msg1; + testMessageNested = msg2; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorReasonNested, "database error"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "nested error!"); +} + +function testNestedOnFailWithErrorBPWithErrorArgsHavingBP() { + foreach var i in data { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + foreach var j in data { + fail error SampleComplexError("nested error!", cause = error("Database Error"), code = 30, pos = [35, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg2), code = errCode2, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testMessage = msg1; + testMessageNested = msg2; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "Database Error"); + assertEquality(testErrorPosRow, 35); + assertEquality(testErrorPosCol, 45); +} + +function testMultiLevelOnFailWithErrorBP() { + string str = ""; + int[] level1dData = [2]; + int[] nestedData = [1]; + + foreach var i in level1dData { + foreach var j in nestedData { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2 -> On Fail Final", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + string str = ""; + int[] nestedData = [1]; + int[] level1dData = [2]; + + foreach var i in level1dData { + foreach var j in nestedData { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +type AssertionError error; + +function assertEquality(any|error expected, any|error actual) { + if expected is anydata && actual is anydata && expected == actual { + return; + } + + if expected === actual { + return; + } + + string expectedValAsString = expected is error ? expected.toString() : expected.toString(); + string actualValAsString = actual is error ? actual.toString() : actual.toString(); + panic error AssertionError("AssertionError", + message = "expected '" + expectedValAsString + "', found '" + actualValAsString + "'"); +} diff --git a/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-semantics-negative.bal b/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-semantics-negative.bal index ef89569e1a7a..13e41969f3a2 100644 --- a/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-semantics-negative.bal +++ b/langlib/langlib-test/src/test/resources/test-src/statements/foreach/foreach-semantics-negative.bal @@ -346,3 +346,31 @@ function testInvalidTupleVarRefWithMismatchingTypesInForeach() { foreach var [[c1, c2, ...c3], c4] in c { } } + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +function testOnFailWithMultipleErrors() { + boolean isPositiveState = false; + int[] nestedData = [1]; + + foreach var i in nestedData { + if isPositiveState { + fail error SampleComplexError("Transaction Failure", code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } on fail var error(msg) { + } +} diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/lock/LocksWithOnFailTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/lock/LocksWithOnFailTest.java index 29e2b04693cf..76247449b2df 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/lock/LocksWithOnFailTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/lock/LocksWithOnFailTest.java @@ -20,11 +20,14 @@ import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BString; +import org.ballerinalang.test.BAssertUtil; import org.ballerinalang.test.BCompileUtil; import org.ballerinalang.test.BRunUtil; import org.ballerinalang.test.CompileResult; +import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; @@ -33,16 +36,18 @@ /** * Tests for Ballerina locks with on fail clause. - * + * * @since 0.961.0 */ public class LocksWithOnFailTest { - private CompileResult compileResult; + private CompileResult compileResult, compileResultNegative; @BeforeClass public void setup() { + compileResult = BCompileUtil.compile("test-src/lock/lock-on-fail.bal"); + compileResultNegative = BCompileUtil.compile("test-src/lock/lock-on-fail-negative.bal"); } @Test(description = "Tests lock within a lock") @@ -71,8 +76,47 @@ public void testOnFailLockWithinLockWithoutVariable() { BRunUtil.invoke(compileResult, "onFailLockWithinLockWithoutVariable"); } + @Test(dataProvider = "onFailClauseWithErrorBPTestDataProvider") + public void testOnFailWithErrorBP(String funcName) { + BRunUtil.invoke(compileResult, funcName); + } + + @DataProvider(name = "onFailClauseWithErrorBPTestDataProvider") + public Object[] onFailClauseWithErrorBPTestDataProvider() { + return new Object[]{ + "testSimpleOnFailWithErrorBP", + "testSimpleOnFailWithErrorBPWithVar", + "testOnFailWithErrorBPHavingUserDefinedTypeWithError", + "testOnFailWithErrorBPHavingUserDefinedTypeWithVar", + "testOnFailWithErrorBPHavingUserDefinedType", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4", + "testOnFailWithErrorBPHavingAnonDetailRecord", + "testOnFailWithErrorBPHavingAnonDetailRecordWithVar", + "testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType", + "testOnFailWithErrorBPWithErrorArgsHavingBP1", + "testOnFailWithErrorBPWithErrorArgsHavingBP2", + "testOnFailWithErrorBPWithErrorArgsHavingBP3", + "testOnFailWithErrorBPWithErrorArgsHavingBP4", + "testOnFailWithErrorBPWithErrorArgsHavingBP5", + "testMultiLevelOnFailWithErrorBP", + "testMultiLevelOnFailWithoutErrorInOneLevel" + }; + } + + @Test(description = "Check incompatible types.") + public void testNegative() { + int i = 0; + BAssertUtil.validateError(compileResultNegative, i++, "invalid error variable; expecting an " + + "error type but found '(SampleComplexError|SampleError)' in type definition", 39, 15); + Assert.assertEquals(compileResultNegative.getErrorCount(), i); + } + @AfterClass public void tearDown() { compileResult = null; + compileResultNegative = null; } } diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/dostatement/DoStmtsTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/dostatement/DoStmtsTest.java index f2fc388ff8ef..6625354f0609 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/dostatement/DoStmtsTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/dostatement/DoStmtsTest.java @@ -31,13 +31,15 @@ */ public class DoStmtsTest { - private CompileResult programFile, negativeFile1, negativeFile2; + private CompileResult programFile, negativeFile1, negativeFile2, negativeFile3; @BeforeClass public void setup() { programFile = BCompileUtil.compile("test-src/statements/dostatement/do-stmt.bal"); negativeFile1 = BCompileUtil.compile("test-src/statements/dostatement/do-stmt-negative-1.bal"); negativeFile2 = BCompileUtil.compile("test-src/statements/dostatement/do-stmt-negative-2.bal"); + negativeFile3 = + BCompileUtil.compile("test-src/statements/dostatement/do-stmt-negative-unreachable.bal"); } @Test @@ -45,32 +47,47 @@ public void testOnFailStatement() { BRunUtil.invoke(programFile, "testOnFailStatement"); } - @Test(description = "Check not incompatible types and reachable statements.") + @Test(description = "Check not incompatible types.") public void testNegative1() { int index = 0; - BAssertUtil.validateError(negativeFile1, index++, "unreachable code", 15, 6); - BAssertUtil.validateWarning(negativeFile1, index++, "unused variable 'e'", 17, 12); BAssertUtil.validateError(negativeFile1, index++, "incompatible error definition type: " + - "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 30, 12); - BAssertUtil.validateWarning(negativeFile1, index++, "unused variable 'e'", 30, 12); - BAssertUtil.validateWarning(negativeFile1, index++, "unused variable 'e'", 43, 12); - BAssertUtil.validateWarning(negativeFile1, index++, "unused variable 'e'", 57, 12); - BAssertUtil.validateError(negativeFile1, index++, "unreachable code", 60, 7); - BAssertUtil.validateError(negativeFile1, index++, "unreachable code", 72, 3); - BAssertUtil.validateError(negativeFile1, index++, "this function must return a result", 73, 1); + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 15, 12); + BAssertUtil.validateError(negativeFile1, index++, "incompatible types: expected 'ErrorTypeA', " + + "found 'ErrorTypeB'", 15, 12); BAssertUtil.validateError(negativeFile1, index++, "incompatible error definition type: " + - "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 90, 12); + "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 37, 12); + BAssertUtil.validateError(negativeFile1, index++, "incompatible types: expected " + + "'(ErrorTypeA|ErrorTypeB)', found 'ErrorTypeA'", 37, 12); Assert.assertEquals(negativeFile1.getDiagnostics().length, index); } + @Test(description = "Check unreachable statements.") + public void testNegativeUnreachable() { + int index = 0; + BAssertUtil.validateError(negativeFile3, index++, "unreachable code", 15, 6); + BAssertUtil.validateWarning(negativeFile3, index++, "unused variable 'e'", 17, 12); + BAssertUtil.validateWarning(negativeFile3, index++, "unused variable 'e'", 30, 12); + BAssertUtil.validateWarning(negativeFile3, index++, "unused variable 'e'", 43, 12); + BAssertUtil.validateWarning(negativeFile3, index++, "unused variable 'e'", 57, 12); + BAssertUtil.validateError(negativeFile3, index++, "unreachable code", 60, 7); + BAssertUtil.validateError(negativeFile3, index++, "unreachable code", 72, 3); + BAssertUtil.validateError(negativeFile3, index++, "this function must return a result", 73, 1); + Assert.assertEquals(negativeFile3.getDiagnostics().length, index); + } + @Test(description = "Check on fail scope.") public void testNegative2() { - Assert.assertEquals(negativeFile2.getErrorCount(), 3); - BAssertUtil.validateError(negativeFile2, 0, "type 'string' not allowed here; " + + int index = 0; + Assert.assertEquals(negativeFile2.getErrorCount(), 5); + BAssertUtil.validateError(negativeFile2, index++, "type 'string' not allowed here; " + "expected an 'error' or a subtype of 'error'.", 6, 11); - BAssertUtil.validateError(negativeFile2, 1, "incompatible types: expected 'string', " + - "found 'error'", 8, 12); - BAssertUtil.validateError(negativeFile2, 2, "undefined symbol 'd'", 26, 12); + BAssertUtil.validateError(negativeFile2, index++, "incompatible error definition " + + "type: 'other' will not be matched to 'string'", 8, 12); + BAssertUtil.validateError(negativeFile2, index++, "incompatible types: expected " + + "'other', found 'string'", 8, 12); + BAssertUtil.validateError(negativeFile2, index++, "invalid error variable; expecting " + + "an error type but found 'string' in type definition", 8, 12); + BAssertUtil.validateError(negativeFile2, index++, "undefined symbol 'd'", 26, 12); } @AfterClass @@ -78,5 +95,6 @@ public void tearDown() { programFile = null; negativeFile1 = null; negativeFile2 = null; + negativeFile3 = null; } } diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/matchstmt/MatchStatementOnFailTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/matchstmt/MatchStatementOnFailTest.java index 6d7d8717e1bd..080a4d748a6c 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/matchstmt/MatchStatementOnFailTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/matchstmt/MatchStatementOnFailTest.java @@ -24,6 +24,7 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -33,12 +34,16 @@ */ public class MatchStatementOnFailTest { - private CompileResult result, resultNegative; + private CompileResult result, resultNegative1, resultNegative2; @BeforeClass public void setup() { result = BCompileUtil.compile("test-src/statements/matchstmt/matchstmt_on_fail.bal"); - resultNegative = BCompileUtil.compile("test-src/statements/matchstmt/matchstmt_on_fail_negative.bal"); + resultNegative1 = + BCompileUtil.compile("test-src/statements/matchstmt/matchstmt_on_fail_negative.bal"); + resultNegative2 = + BCompileUtil.compile("test-src/statements/matchstmt/matchstmt_on_fail" + + "_negative_unreachable.bal"); } @Test(description = "Test basics of static pattern match statement with fail statement") @@ -71,29 +76,71 @@ public void testVarInMatchPatternWithinOnfail() { BRunUtil.invoke(result, "testVarInMatchPatternWithinOnfail", new Object[]{}); } - @Test(description = "Check not incompatible types and reachable statements.") + @Test(dataProvider = "onFailClauseWithErrorBPTestDataProvider") + public void testOnFailWithErrorBP(String funcName) { + BRunUtil.invoke(result, funcName); + } + + @DataProvider(name = "onFailClauseWithErrorBPTestDataProvider") + public Object[] onFailClauseWithErrorBPTestDataProvider() { + return new Object[]{ + "testSimpleOnFailWithErrorBP", + "testSimpleOnFailWithErrorBPWithVar", + "testOnFailWithErrorBPHavingUserDefinedTypeWithError", + "testOnFailWithErrorBPHavingUserDefinedTypeWithVar", + "testOnFailWithErrorBPHavingUserDefinedType", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4", + "testOnFailWithErrorBPHavingAnonDetailRecord", + "testOnFailWithErrorBPHavingAnonDetailRecordWithVar", + "testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType", + "testOnFailWithErrorBPWithErrorArgsHavingBP1", + "testOnFailWithErrorBPWithErrorArgsHavingBP2", + "testOnFailWithErrorBPWithErrorArgsHavingBP3", + "testOnFailWithErrorBPWithErrorArgsHavingBP4", + "testOnFailWithErrorBPWithErrorArgsHavingBP5", + "testMultiLevelOnFailWithErrorBP", + "testMultiLevelOnFailWithoutErrorInOneLevel" + }; + } + + @Test(description = "Check incompatible types.") public void testNegative1() { - int i = -1; - BAssertUtil.validateError(resultNegative, ++i, "unreachable code", 29, 14); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'e'", 31, 15); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'err'", 56, 14); - BAssertUtil.validateError(resultNegative, ++i, "incompatible error definition type: " + + int i = 0; + BAssertUtil.validateError(resultNegative1, i++, "incompatible error definition type: " + + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 30, 15); + BAssertUtil.validateError(resultNegative1, i++, "incompatible types: " + + "expected 'ErrorTypeA', found 'ErrorTypeB'", 30, 15); + BAssertUtil.validateError(resultNegative1, i++, "incompatible error definition type: " + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 59, 15); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'e'", 59, 15); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'err'", 85, 14); - BAssertUtil.validateError(resultNegative, ++i, "incompatible error definition type: " + - "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 88, 15); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'e'", 88, 15); - BAssertUtil.validateError(resultNegative, ++i, "unreachable code", 90, 9); - BAssertUtil.validateError(resultNegative, ++i, "incompatible error definition type: " + - "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 124, 15); - BAssertUtil.validateWarning(resultNegative, ++i, "unused variable 'e'", 124, 15); - Assert.assertEquals(resultNegative.getDiagnostics().length, i + 1); + BAssertUtil.validateError(resultNegative1, i++, "incompatible types: " + + "expected 'ErrorTypeA', found 'ErrorTypeB'", 59, 15); + BAssertUtil.validateError(resultNegative1, i++, "incompatible error definition type: " + + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 94, 15); + BAssertUtil.validateError(resultNegative1, i++, "incompatible types: " + + "expected '(ErrorTypeA|ErrorTypeB)', found 'ErrorTypeB'", 94, 15); + BAssertUtil.validateError(resultNegative1, i++, "invalid error variable; expecting an error " + + "type but found '(SampleComplexError|SampleError)' in type definition", 125, 15); + Assert.assertEquals(resultNegative1.getErrorCount(), i); + } + + @Test(description = "Check reachable statements.") + public void testNegative2() { + int i = -1; + BAssertUtil.validateError(resultNegative2, ++i, "unreachable code", 29, 14); + BAssertUtil.validateWarning(resultNegative2, ++i, "unused variable 'e'", 31, 15); + BAssertUtil.validateWarning(resultNegative2, ++i, "unused variable 'err'", 57, 14); + BAssertUtil.validateWarning(resultNegative2, ++i, "unused variable 'e'", 60, 15); + BAssertUtil.validateError(resultNegative2, ++i, "unreachable code", 62, 9); + Assert.assertEquals(resultNegative2.getDiagnostics().length, i + 1); } @AfterClass public void tearDown() { result = null; - resultNegative = null; + resultNegative1 = null; + resultNegative2 = null; } } diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/onfail/OnFailClauseTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/onfail/OnFailClauseTest.java index c5a389b1b910..dfed4e304043 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/onfail/OnFailClauseTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/onfail/OnFailClauseTest.java @@ -51,8 +51,60 @@ public void testOnFailClause() { public void testOnFailClauseNegativeCaseV1() { CompileResult negativeResult = BCompileUtil.compile( "test-src/statements/onfail/on-fail-clause-negative.bal"); - Assert.assertEquals(negativeResult.getErrorCount(), 1); - BAssertUtil.validateError(negativeResult, 0, "undefined symbol 'i'", 22, 55); + int i = 0; + BAssertUtil.validateError(negativeResult, i++, "undefined symbol 'i'", 22, 55); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: " + + "'SampleError' will not be matched to 'error'", 49, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'SampleError', " + + "found 'error'", 49, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: " + + "'SampleError' will not be matched to 'SampleComplexError'", 56, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'SampleError', " + + "found 'SampleComplexError'", 56, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: " + + "'SampleError' will not be matched to 'int'", 63, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'SampleError', " + + "found 'int'", 63, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found 'int' in type definition", 63, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found 'int' in type definition", 63, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: " + + "'error' will not be matched to " + + "'error'", 71, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'error', found 'error'", 71, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: 'error' " + + "will not be matched to 'anydata'", 78, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'error', " + + "found 'anydata'", 78, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found 'anydata' in type definition", 78, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found 'anydata' in type definition", 78, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible error definition type: 'error' will" + + " not be matched to '[error]'", 85, 15); + BAssertUtil.validateError(negativeResult, i++, "incompatible types: expected 'error', " + + "found '[error]'", 85, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid binding pattern in 'on fail' clause: " + + "only a capture binding pattern or an error binding pattern is allowed", 85, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found '[error]' in type definition", 85, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid binding pattern in 'on fail' clause: " + + "only a capture binding pattern or an error binding pattern is allowed", 92, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid list binding pattern: attempted " + + "to infer a list type, but found 'error'", 92, 15); + BAssertUtil.validateError(negativeResult, i++, "a wildcard binding pattern can be used only " + + "with a value that belong to type 'any'", 99, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid binding pattern in 'on fail' clause: " + + "only a capture binding pattern or an error binding pattern is allowed", 106, 15); + BAssertUtil.validateError(negativeResult, i++, "invalid record binding pattern " + + "with type 'error'", 106, 15); + BAssertUtil.validateError(negativeResult, i++, "unknown error detail arg 'cause' passed to " + + "closed error detail type 'SampleComplexErrorData'", 114, 66); + BAssertUtil.validateError(negativeResult, i++, "invalid error variable; expecting an error " + + "type but found '(SampleComplexError|SampleError)' in type definition", 117, 15); + Assert.assertEquals(negativeResult.getErrorCount(), i); } @Test(description = "Test on-fail clause negative cases - v2") diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/retrystmt/RetryStmtWithOnFailTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/retrystmt/RetryStmtWithOnFailTest.java index a48f0b796c95..80af1463707d 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/retrystmt/RetryStmtWithOnFailTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/retrystmt/RetryStmtWithOnFailTest.java @@ -24,6 +24,7 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -31,12 +32,14 @@ */ public class RetryStmtWithOnFailTest { - private CompileResult programFile, negativeFile; + private CompileResult programFile, negativeFile1, negativeFile2; @BeforeClass public void setup() { programFile = BCompileUtil.compile("test-src/statements/retrystmt/retry_stmt_with_on_fail.bal"); - negativeFile = BCompileUtil.compile("test-src/statements/retrystmt/retry_on_fail_negative.bal"); + negativeFile1 = BCompileUtil.compile("test-src/statements/retrystmt/retry_on_fail_negative.bal"); + negativeFile2 = BCompileUtil.compile("test-src/statements/retrystmt/retry_on_fail_negative_unreachable.bal"); + } @Test @@ -45,28 +48,69 @@ public void testRetryStatement() { BRunUtil.invoke(programFile, "testRetryStatement", params); } - @Test(description = "Check not incompatible types and reachable statements.") + @Test(dataProvider = "onFailClauseWithErrorBPTestDataProvider") + public void testOnFailWithErrorBP(String funcName) { + BRunUtil.invoke(programFile, funcName); + } + + @DataProvider(name = "onFailClauseWithErrorBPTestDataProvider") + public Object[] onFailClauseWithErrorBPTestDataProvider() { + return new Object[]{ + "testSimpleOnFailWithErrorBP", + "testSimpleOnFailWithErrorBPWithVar", + "testOnFailWithErrorBPHavingUserDefinedTypeWithError", + "testOnFailWithErrorBPHavingUserDefinedTypeWithVar", + "testOnFailWithErrorBPHavingUserDefinedType", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4", + "testOnFailWithErrorBPHavingAnonDetailRecord", + "testOnFailWithErrorBPHavingAnonDetailRecordWithVar", + "testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType", + "testOnFailWithErrorBPWithErrorArgsHavingBP1", + "testOnFailWithErrorBPWithErrorArgsHavingBP2", + "testOnFailWithErrorBPWithErrorArgsHavingBP3", + "testOnFailWithErrorBPWithErrorArgsHavingBP4", + "testOnFailWithErrorBPWithErrorArgsHavingBP5", + "testMultiLevelOnFailWithErrorBP", + "testMultiLevelOnFailWithoutErrorInOneLevel" + }; + } + + @Test(description = "Check not incompatible types.") public void testNegative1() { int index = 0; - BAssertUtil.validateError(negativeFile, index++, "unreachable code", 20, 12); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'e'", 21, 16); - BAssertUtil.validateError(negativeFile, index++, "incompatible error definition type: " + - "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 32, 14); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'e'", 32, 14); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'e'", 45, 12); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'e'", 59, 12); - BAssertUtil.validateError(negativeFile, index++, "unreachable code", 62, 7); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'e1'", 78, 12); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'resA'", 97, 6); - BAssertUtil.validateWarning(negativeFile, index++, "unused variable 'resB'", 98, 6); - BAssertUtil.validateError(negativeFile, index++, "incompatible error definition type: " + - "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 100, 12); - Assert.assertEquals(negativeFile.getDiagnostics().length, index); + BAssertUtil.validateError(negativeFile1, index++, "incompatible error definition type: " + + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 14, 14); + BAssertUtil.validateError(negativeFile1, index++, "incompatible types: " + + "expected 'ErrorTypeA', found 'ErrorTypeB'", 14, 14); + BAssertUtil.validateError(negativeFile1, index++, "incompatible error definition type: " + + "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 36, 12); + BAssertUtil.validateError(negativeFile1, index++, "incompatible types: " + + "expected '(ErrorTypeA|ErrorTypeB)', found 'ErrorTypeA'", 36, 12); + BAssertUtil.validateError(negativeFile1, index++, "invalid error variable; " + + "expecting an error type but found '(SampleComplexError|SampleError)' in type definition", 66, 15); + Assert.assertEquals(negativeFile1.getDiagnostics().length, index); + } + + @Test(description = "Check unreachable statements.") + public void testNegative2() { + int index = 0; + BAssertUtil.validateError(negativeFile2, index++, "unreachable code", 20, 12); + BAssertUtil.validateWarning(negativeFile2, index++, "unused variable 'e'", 21, 16); + BAssertUtil.validateWarning(negativeFile2, index++, "unused variable 'e'", 33, 12); + BAssertUtil.validateError(negativeFile2, index++, "unreachable code", 36, 7); + BAssertUtil.validateWarning(negativeFile2, index++, "unused variable 'e'", 48, 12); + BAssertUtil.validateWarning(negativeFile2, index++, "unused variable 'e1'", 66, 12); + BAssertUtil.validateWarning(negativeFile2, index++, "unused variable 'resB'", 81, 6); + Assert.assertEquals(negativeFile2.getDiagnostics().length, index); } @AfterClass public void tearDown() { programFile = null; - negativeFile = null; + negativeFile1 = null; + negativeFile2 = null; } } diff --git a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/whilestatement/WhileStmtTest.java b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/whilestatement/WhileStmtTest.java index 85482694d268..4d158ecdb502 100644 --- a/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/whilestatement/WhileStmtTest.java +++ b/tests/jballerina-unit-test/src/test/java/org/ballerinalang/test/statements/whilestatement/WhileStmtTest.java @@ -25,6 +25,7 @@ import org.ballerinalang.test.CompileResult; import org.testng.Assert; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -38,6 +39,7 @@ public class WhileStmtTest { private CompileResult negativeCompileResult; private CompileResult onfailCompileResult; private CompileResult onfailNegativeCompileResult; + private CompileResult onfailNegativeUnreachableCompileResult; @BeforeClass public void setup() { @@ -46,6 +48,8 @@ public void setup() { onfailCompileResult = BCompileUtil.compile("test-src/statements/whilestatement/while-stmt-on-fail.bal"); onfailNegativeCompileResult = BCompileUtil.compile( "test-src/statements/whilestatement/while-stmt-on-fail-negative.bal"); + onfailNegativeUnreachableCompileResult = BCompileUtil.compile( + "test-src/statements/whilestatement/while-stmt-on-fail-negative-reachability.bal"); } @Test(description = "Test while loop with a condition which evaluates to true") @@ -242,25 +246,46 @@ public void testNestedWhileStmtLoopTerminationWithFail() { Assert.assertEquals(actual, expected); } - @Test(description = "Check not incompatible types and reachable statements.") + @Test(description = "Check incompatible types.") public void testNegative1() { int index = 0; - BAssertUtil.validateError(onfailNegativeCompileResult, index++, "unreachable code", 17, 6); - BAssertUtil.validateWarning(onfailNegativeCompileResult, index++, "unused variable 'e'", 19, 12); BAssertUtil.validateError(onfailNegativeCompileResult, index++, "incompatible error definition type: " + - "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 34, 12); - BAssertUtil.validateWarning(onfailNegativeCompileResult, index++, "unused variable 'e'", 34, 12); - BAssertUtil.validateWarning(onfailNegativeCompileResult, index++, "unused variable 'e'", 49, 12); - BAssertUtil.validateWarning(onfailNegativeCompileResult, index++, "unused variable 'e'", 65, 12); - BAssertUtil.validateError(onfailNegativeCompileResult, index++, "unreachable code", 68, 7); - BAssertUtil.validateError(onfailNegativeCompileResult, index++, "this function must return a result", 83, 1); + "'ErrorTypeA' will not be matched to 'ErrorTypeB'", 17, 12); + BAssertUtil.validateError(onfailNegativeCompileResult, index++, + "incompatible types: expected 'ErrorTypeA', found 'ErrorTypeB'", 17, 12); BAssertUtil.validateError(onfailNegativeCompileResult, index++, "incompatible error definition type: " + - "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 102, 12); - BAssertUtil.validateError(onfailNegativeCompileResult, index++, "unreachable code", 116, 9); - BAssertUtil.validateError(onfailNegativeCompileResult, index++, "unreachable code", 118, 5); + "'ErrorTypeB' will not be matched to 'ErrorTypeA'", 41, 12); + BAssertUtil.validateError(onfailNegativeCompileResult, index++, + "incompatible types: expected '(ErrorTypeA|ErrorTypeB)', found 'ErrorTypeA'", 41, 12); + BAssertUtil.validateError(onfailNegativeCompileResult, index++, "invalid error variable; " + + "expecting an error type but found '(SampleComplexError|SampleError)' in type definition", 72, 15); Assert.assertEquals(onfailNegativeCompileResult.getDiagnostics().length, index); } + @Test(description = "Check unreachable statements.") + public void testNegative2() { + int index = 0; + BAssertUtil.validateError(onfailNegativeUnreachableCompileResult, index++, + "unreachable code", 17, 6); + BAssertUtil.validateWarning(onfailNegativeUnreachableCompileResult, index++, + "unused variable 'e'", 19, 12); + BAssertUtil.validateWarning(onfailNegativeUnreachableCompileResult, index++, + "unused variable 'e'", 34, 12); + BAssertUtil.validateWarning(onfailNegativeUnreachableCompileResult, index++, + "unused variable 'e'", 49, 12); + BAssertUtil.validateWarning(onfailNegativeUnreachableCompileResult, index++, + "unused variable 'e'", 65, 12); + BAssertUtil.validateError(onfailNegativeUnreachableCompileResult, index++, + "unreachable code", 68, 7); + BAssertUtil.validateError(onfailNegativeUnreachableCompileResult, index++, + "this function must return a result", 83, 1); + BAssertUtil.validateError(onfailNegativeUnreachableCompileResult, index++, + "unreachable code", 111, 9); + BAssertUtil.validateError(onfailNegativeUnreachableCompileResult, index++, + "unreachable code", 113, 5); + Assert.assertEquals(onfailNegativeUnreachableCompileResult.getDiagnostics().length, index); + } + @Test(description = "Test type narrowing for while statement") public void testWhileStmtTypeNarrowing() { CompileResult compileResult = @@ -297,6 +322,38 @@ public void testWhileStmtTypeNarrowing() { Assert.assertEquals(compileResult.getDiagnostics().length, index); } + @Test(dataProvider = "onFailClauseWithErrorBPTestDataProvider") + public void testOnFailWithErrorBP(String funcName) { + BRunUtil.invoke(onfailCompileResult, funcName); + } + + @DataProvider(name = "onFailClauseWithErrorBPTestDataProvider") + public Object[] onFailClauseWithErrorBPTestDataProvider() { + return new Object[]{ + "testSimpleOnFailWithErrorBP", + "testSimpleOnFailWithErrorBPWithVar", + "testOnFailWithErrorBPHavingUserDefinedTypeWithError", + "testOnFailWithErrorBPHavingUserDefinedTypeWithVar", + "testOnFailWithErrorBPHavingUserDefinedType", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3", + "testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4", + "testOnFailWithErrorBPHavingAnonDetailRecord", + "testOnFailWithErrorBPHavingAnonDetailRecordWithVar", + "testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType", + "testOnFailWithErrorBPWithErrorArgsHavingBP1", + "testOnFailWithErrorBPWithErrorArgsHavingBP2", + "testOnFailWithErrorBPWithErrorArgsHavingBP3", + "testOnFailWithErrorBPWithErrorArgsHavingBP4", + "testOnFailWithErrorBPWithErrorArgsHavingBP5", + "testNestedOnFailWithErrorBP", + "testNestedOnFailWithErrorBPWithErrorArgsHavingBP", + "testMultiLevelOnFailWithErrorBP", + "testMultiLevelOnFailWithoutErrorInOneLevel" + }; + } + @Test(description = "Test type narrowing for while statement with no errors") public void testWhileStmtTypeNarrowPositive() { CompileResult compileResult = diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail-negative.bal new file mode 100644 index 000000000000..ab589b6939f9 --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail-negative.bal @@ -0,0 +1,41 @@ +// Copyright (c) 2023 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// +// WSO2 Inc. licenses this file to you 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. + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +function testOnFailWithMultipleErrors() { + boolean isPositiveState = false; + lock { + if isPositiveState { + fail error SampleComplexError("Transaction Failure", code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } on fail var error(msg) { + } +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail.bal b/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail.bal index c894d20f005c..6aee2677d874 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/lock/lock-on-fail.bal @@ -89,6 +89,357 @@ function getError() returns int|error { return err; } +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; + +function testSimpleOnFailWithErrorBP() { + lock { + lockWithinLockInt1 = 99; + fail error("error!"); + } on fail error error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + lock { + lockWithinLockInt1 = 99; + fail error("error!"); + } on fail var error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + lock { + lockWithinLockInt1 = 99; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + lock { + lockWithinLockInt1 = 99; + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + lock { + lockWithinLockInt1 = 99; + error errVar = error("error", code = 34); + fail errVar; + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); + assertEquality(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + lock { + lockWithinLockInt1 = 99; + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg; + lock { + lockWithinLockInt1 = 99; + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(causeMsg, "Database Error"); + assertEquality(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + lock { + lockWithinLockInt1 = 99; + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + lock { + lockWithinLockInt1 = 99; + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + lock { + lockWithinLockInt1 = 99; + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + lock { + lockWithinLockInt1 = 99; + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testMultiLevelOnFailWithErrorBP() { + int i = 2; + string str = ""; + + lock { + lock { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2 -> On Fail Final", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + int i = 2; + string str = ""; + + lock { + lock { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + function assertEquality(anydata expected, anydata actual) { if expected == actual { return; diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-1.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-1.bal index 35d5c44c49e2..3d55e383edd2 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-1.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-1.bal @@ -6,21 +6,6 @@ type ErrorTypeB distinct error; const TYPE_B_ERROR_REASON = "TypeB_Error"; -function testUnreachableAfterFail () returns string { - string str = ""; - do { - error err = error("custom error", message = "error value"); - str += "Before failure throw"; - fail err; - str += "After failure throw"; - } - on fail error e { - str += "-> Error caught ! "; - } - str += "-> Execution continues..."; - return str; -} - function testIncompatibleErrorTypeOnFail () returns string { string str = ""; do { @@ -34,44 +19,6 @@ function testIncompatibleErrorTypeOnFail () returns string { return str; } -function testIgnoreReturnInOnFail () returns string { - string str = ""; - do { - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - } - str += "-> Execution continues..."; - return str; -} - -function testUnreachableInOnFail () returns string { - string str = ""; - do { - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - str += "-> After returning string"; - } - str += "-> Execution continues..."; - return str; -} - -function testReturnWitihinDo() returns string { - string str = ""; - do { - str = str + "do statement start"; - return str; - } - str = str + "do statemtnt finished"; -} - function testOnFailWithUnion () returns string { string str = ""; var getTypeAError = function () returns int|ErrorTypeA{ diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-unreachable.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-unreachable.bal new file mode 100644 index 000000000000..aeba1771f56e --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/dostatement/do-stmt-negative-unreachable.bal @@ -0,0 +1,73 @@ +type ErrorTypeA distinct error; + +const TYPE_A_ERROR_REASON = "TypeA_Error"; + +type ErrorTypeB distinct error; + +const TYPE_B_ERROR_REASON = "TypeB_Error"; + +function testUnreachableAfterFail () returns string { + string str = ""; + do { + error err = error("custom error", message = "error value"); + str += "Before failure throw"; + fail err; + str += "After failure throw"; + } + on fail error e { + str += "-> Error caught ! "; + } + str += "-> Execution continues..."; + return str; +} + +function testIncompatibleErrorTypeOnFail () returns string { + string str = ""; + do { + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + } + str += "-> Execution continues..."; + return str; +} + +function testIgnoreReturnInOnFail () returns string { + string str = ""; + do { + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + } + str += "-> Execution continues..."; + return str; +} + +function testUnreachableInOnFail () returns string { + string str = ""; + do { + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + str += "-> After returning string"; + } + str += "-> Execution continues..."; + return str; +} + +function testReturnWitihinDo() returns string { + string str = ""; + do { + str = str + "do statement start"; + return str; + } + str = str + "do statemtnt finished"; +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail.bal index 1d2410d83ede..9efddb0c737f 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail.bal @@ -361,6 +361,437 @@ function getErrorDetailNestedMatch([int, string] dataEntry) returns string { return str; } +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; +string matchString = "fail"; +string matchRes = ""; + +function testSimpleOnFailWithErrorBP() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error("error!"); + } + } on fail error error(msg) { + testMessage = msg; + } + assertEquals(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error("error!"); + } + } on fail var error(msg) { + testMessage = msg; + } + assertEquals(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquals(testMessage, "error!"); + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquals(testMessage, "error!"); + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquals(testMessage, "error!"); + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquals(testMessage, "error!"); + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquals(testErrorCode, 34); + assertEquals(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquals(testErrorCode, 34); + assertEquals(testErrorCode is int, true); + assertEquals(testErrorReason is string, true); + assertEquals(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquals(testErrorCode, 34); + assertEquals(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg; + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquals(testErrorPosRow, 30); + assertEquals(testErrorPosRow is int, true); + assertEquals(testErrorPosCol, 45); + assertEquals(testErrorPosCol is int, true); + assertEquals(testErrorMoreInfo, "deadlock condition"); + assertEquals(testErrorMoreInfo is string, true); + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); + assertEquals(causeMsg, "Database Error"); + assertEquals(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquals(testErrorPosRow, 30); + assertEquals(testErrorPosRow is int, true); + assertEquals(testErrorPosCol, 45); + assertEquals(testErrorPosCol is int, true); + assertEquals(testErrorMoreInfo, "deadlock condition"); + assertEquals(testErrorMoreInfo is string, true); + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); + assertEquals(testMessage, "Database Error"); + assertEquals(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquals(testErrorPosRow, 30); + assertEquals(testErrorPosRow is int, true); + assertEquals(testErrorPosCol, 45); + assertEquals(testErrorPosCol is int, true); + assertEquals(testErrorMoreInfo, "deadlock condition"); + assertEquals(testErrorMoreInfo is string, true); + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); + assertEquals(testMessage, "Database Error"); + assertEquals(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquals(testErrorPosRow, 30); + assertEquals(testErrorPosRow is int, true); + assertEquals(testErrorPosCol, 45); + assertEquals(testErrorPosCol is int, true); + assertEquals(testErrorMoreInfo, "deadlock condition"); + assertEquals(testErrorMoreInfo is string, true); + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); + assertEquals(testMessage, "Database Error"); + assertEquals(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquals(testErrorPosRow, 30); + assertEquals(testErrorPosRow is int, true); + assertEquals(testErrorPosCol, 45); + assertEquals(testErrorPosCol is int, true); + assertEquals(testErrorMoreInfo, "deadlock condition"); + assertEquals(testErrorMoreInfo is string, true); + assertEquals(testErrorCode, 20); + assertEquals(testErrorCode is int, true); + assertEquals(testMessage, "Database Error"); + assertEquals(testMessage is string, true); +} + +function testMultiLevelOnFailWithErrorBP() { + int i = 2; + string str = ""; + + while i <= 2 { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 30, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + fail error SampleError("database error!", code = 20, reason = "database connection error"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquals(" -> Iteration 2, -> On Fail #2 -> On Fail Final", str); + assertEquals(testErrorCode, 30); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + int i = 2; + string str = ""; + + while i <= 2 { + match matchString { + 12 => { + matchRes = "12"; + } + "fail" => { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquals(" -> Iteration 2, -> On Fail #2", str); + assertEquals(testErrorCode, 20); + assertEquals(testErrorReason, "deadlock condition"); + assertEquals(testMessage, "error!"); +} + function assertEquals(anydata expected, anydata actual) { if expected == actual { return; diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative.bal index 700028927c56..c7086297cfae 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative.bal @@ -6,35 +6,6 @@ type ErrorTypeB distinct error; const TYPE_B_ERROR_REASON = "TypeB_Error"; -function testUnreachableAfterFail(string | int | boolean a) returns string|error { - match a { - 12 => { - return "Value is '12'"; - } - "Hello" => { - return "Value is 'Hello'"; - } - 15 => { - return "Value is '15'"; - } - true => { - return "Value is 'true'"; - } - false => { - return "Value is 'false'"; - } - "fail" => { - error err = error("custom error", message = "error value"); - fail err; - return "After failure throw"; - } - } on fail error e { - return "Value is 'error'"; - } - - return "Value is 'Default'"; -} - function testIncompatibleErrorTypeOnFail(string | int | boolean a) returns string|error { match a { 12 => { @@ -87,7 +58,6 @@ function testUnreachableInOnFail(string | int | boolean a) returns string|error } } on fail ErrorTypeB e { return "Value is 'error'"; - str += "-> After returning string"; } return "Value is 'Default'"; @@ -127,3 +97,31 @@ function testOnFailErrorType(string | int | boolean a) returns string|error { return "Value is 'Default'"; } + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +function testOnFailWithMultipleErrors() { + string matchString = "fail"; + match matchString { + 12 => { + fail error SampleComplexError("Transaction Failure", code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + "fail" => { + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } + } on fail var error(msg) { + } +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative_unreachable.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative_unreachable.bal new file mode 100644 index 000000000000..cadc30c4819f --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/matchstmt/matchstmt_on_fail_negative_unreachable.bal @@ -0,0 +1,66 @@ +type ErrorTypeA distinct error; + +const TYPE_A_ERROR_REASON = "TypeA_Error"; + +type ErrorTypeB distinct error; + +const TYPE_B_ERROR_REASON = "TypeB_Error"; + +function testUnreachableAfterFail(string | int | boolean a) returns string|error { + match a { + 12 => { + return "Value is '12'"; + } + "Hello" => { + return "Value is 'Hello'"; + } + 15 => { + return "Value is '15'"; + } + true => { + return "Value is 'true'"; + } + false => { + return "Value is 'false'"; + } + "fail" => { + error err = error("custom error", message = "error value"); + fail err; + return "After failure throw"; + } + } on fail error e { + return "Value is 'error'"; + } + + return "Value is 'Default'"; +} + +function testUnreachableInOnFail(string | int | boolean a) returns string|error { + string str = ""; + match a { + 12 => { + return "Value is '12'"; + } + "Hello" => { + return "Value is 'Hello'"; + } + 15 => { + return "Value is '15'"; + } + true => { + return "Value is 'true'"; + } + false => { + return "Value is 'false'"; + } + "fail" => { + error err = error("custom error", message = "error value"); + fail error ErrorTypeB(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + } on fail ErrorTypeB e { + return "Value is 'error'"; + str += "-> After returning string"; + } + + return "Value is 'Default'"; +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause-negative.bal index 53aa6db3fa9e..51355c30d19d 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause-negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause-negative.bal @@ -27,3 +27,93 @@ function getError() returns error { error err = error("Custom Error"); return err; } + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +function testOnFailWithErrorBPHavingMismatchedTypes1() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + } +} + +function testOnFailWithErrorBPHavingMismatchedTypes2() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleComplexError error(code = errCode) { + } +} + +function testOnFailWithErrorBPHavingMismatchedTypes3() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail int error(code = errCode) { + } +} + +function testOnFailWithErrorBPHavingMismatchedTypes4() { + do { + error errVar = error("error", code = "23"); + fail errVar; + } on fail error error(code = errorCode) { + } +} + +function testOnFailWithErrorBPHavingMismatchedTypes5() { + do { + fail error("error!"); + } on fail anydata error(msg) { + } +} + +function testOnFailWithErrorBPHavingInvalidListBP1() { + do { + fail error("error!"); + } on fail [error] [err] { + } +} + +function testOnFailWithErrorBPHavingInvalidListBP2() { + do { + fail error("error!"); + } on fail error [err] { + } +} + +function testOnFailWithErrorBPHavingInvalidWildcardBP() { + do { + fail error("error!"); + } on fail error _ { + } +} + +function testOnFailWithErrorBPHavingInvalidMappingBP() { + do { + fail error("error!"); + } on fail error {failError: err} { + } +} + +function testOnFailWithMultipleErrors() { + boolean isPositiveState = false; + do { + if isPositiveState { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } on fail var error(msg) { + } +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause.bal index e2503b8b7f1b..c105eec2be31 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/onfail/on-fail-clause.bal @@ -588,6 +588,397 @@ function testOnFailInAnonFunctionExpr() returns error? { assertEquality((result2).detail().get("message"), "'string' value 'a2' cannot be converted to 'int'"); } +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; + +function testSimpleOnFailWithErrorBP() { + do { + fail error("error!"); + } on fail error error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + do { + fail error("error!"); + } on fail var error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + do { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + do { + error errVar = error("error", code = 34); + fail errVar; + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); + assertEquality(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + do { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg; + do { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(causeMsg, "Database Error"); + assertEquality(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + do { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + do { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + do { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + do { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +int testErrorCodeNested = 0; +string testMessageNested = ""; + +function testNestedOnFailWithErrorBP() { + string testErrorReasonNested = ""; + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + do { + fail error SampleError("nested error!", code = 30, reason = "database error"); + } on fail var error(msg2, code = errCode2, reason = errReason2) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testErrorReason = errReason1; + testErrorReasonNested = errReason2; + testMessage = msg1; + testMessageNested = msg2; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorReasonNested, "database error"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "nested error!"); +} + +function testNestedOnFailWithErrorBPWithErrorArgsHavingBP() { + do { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + do { + fail error SampleComplexError("nested error!", cause = error("Database Error"), code = 30, pos = [35, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg2), code = errCode2, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testMessage = msg1; + testMessageNested = msg2; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "Database Error"); + assertEquality(testErrorPosRow, 35); + assertEquality(testErrorPosCol, 45); +} + +function testMultiLevelOnFailWithErrorBP() { + int i = 2; + string str = ""; + + while i <= 2 { + do { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2 -> On Fail Final", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + int i = 2; + string str = ""; + + while i <= 2 { + do { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} //------------------------------------------------------------------------------- type AssertionError error; diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative.bal index 5266413d7b62..abc2f5020e79 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative.bal @@ -6,24 +6,6 @@ type ErrorTypeB distinct error; const TYPE_B_ERROR_REASON = "TypeB_Error"; -function trxError() returns error { - return error("TransactionError"); -} - -function testUnreachableAfterFail () returns string|error { - string str = ""; - int count = 0; - retry (3) { - count = count+1; - str += (" attempt " + count.toString() + ":error,"); - fail trxError(); - str += (" attempt "+ count.toString() + ":result returned end."); - } on fail error e { - return error("Custom Error"); - } - return str; -} - function testIncompatibleErrorTypeOnFail () returns string { string str = ""; retry(3) { @@ -36,52 +18,6 @@ function testIncompatibleErrorTypeOnFail () returns string { return str; } -function testIgnoreReturnInOnFail () returns string { - string str = ""; - retry(3) { - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - } - str += "-> Execution continues..."; - return str; -} - -function testUnreachableInOnFail () returns string { - string str = ""; - retry(3) { - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - str += "-> After returning string"; - } - str += "-> Execution continues..."; - return str; -} - -function testNestedRetryWithLessOnFails () returns string { - string str = ""; - retry(3) { - str += "-> Before error 1 is thrown"; - retry(2) { - str += " -> Before error 2 is thrown"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail error e1 { - str += " -> Error caught !"; - } - str += "-> Execution continues..."; - return str; -} - function testOnFailWithUnion () returns string { string str = ""; var getTypeAError = function () returns int|ErrorTypeA{ @@ -104,3 +40,29 @@ function testOnFailWithUnion () returns string { str += "-> Execution continues..."; return str; } + +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +function testOnFailWithMultipleErrors() { + boolean isPositiveState = false; + retry(3) { + if isPositiveState { + fail error SampleComplexError("Transaction Failure", code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } on fail var error(msg) { + } +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative_unreachable.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative_unreachable.bal new file mode 100644 index 000000000000..1a8fd4f143ce --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_on_fail_negative_unreachable.bal @@ -0,0 +1,89 @@ +type ErrorTypeA distinct error; + +const TYPE_A_ERROR_REASON = "TypeA_Error"; + +const TYPE_B_ERROR_REASON = "TypeB_Error"; + +type ErrorTypeB distinct error; + +function trxError() returns error { + return error("TransactionError"); +} + +function testUnreachableAfterFail () returns string|error { + string str = ""; + int count = 0; + retry (3) { + count = count+1; + str += (" attempt " + count.toString() + ":error,"); + fail trxError(); + str += (" attempt "+ count.toString() + ":result returned end."); + } on fail error e { + return error("Custom Error"); + } + return str; +} + +function testUnreachableInOnFail () returns string { + string str = ""; + retry(3) { + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + str += "-> After returning string"; + } + str += "-> Execution continues..."; + return str; +} + +function testIgnoreReturnInOnFail () returns string { + string str = ""; + retry(3) { + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + } + str += "-> Execution continues..."; + return str; +} + +function testNestedRetryWithLessOnFails () returns string { + string str = ""; + retry(3) { + str += "-> Before error 1 is thrown"; + retry(2) { + str += " -> Before error 2 is thrown"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail error e1 { + str += " -> Error caught !"; + } + str += "-> Execution continues..."; + return str; +} + +function testOnFailWithUnion () returns string { + string str = ""; + var getTypeBError = function () returns int|ErrorTypeB{ + ErrorTypeB errorB = error ErrorTypeB(TYPE_B_ERROR_REASON, message = "Error Type B"); + return errorB; + }; + retry(3) { + str += "Before failure throw"; + int resB = check getTypeBError(); + } + on fail ErrorTypeB e { + str += "-> Error caught : "; + str = str.concat(e.message()); + } + str += "-> Execution continues..."; + return str; +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_stmt_with_on_fail.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_stmt_with_on_fail.bal index a97c7d788e2d..6551a1c430bb 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_stmt_with_on_fail.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/retrystmt/retry_stmt_with_on_fail.bal @@ -289,6 +289,398 @@ function testNestedRetryOnFailJump2() returns string { return str; } +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; + +function testSimpleOnFailWithErrorBP() { + retry(3) { + fail error("error!"); + } on fail error error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + retry(3) { + fail error("error!"); + } on fail var error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + retry(3) { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + retry(3) { + error errVar = error("error", code = 34); + fail errVar; + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); + assertEquality(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + retry(3) { + error errVar = error("error", code = 34); + fail errVar; + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg; + retry(3) { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(causeMsg, "Database Error"); + assertEquality(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + retry(3) { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + retry(3) { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + retry(3) { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + retry(3) { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +int testErrorCodeNested = 0; +string testMessageNested = ""; + +function testNestedOnFailWithErrorBP() { + string testErrorReasonNested = ""; + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + retry(3) { + fail error SampleError("nested error!", code = 30, reason = "database error"); + } on fail var error(msg2, code = errCode2, reason = errReason2) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testErrorReason = errReason1; + testErrorReasonNested = errReason2; + testMessage = msg1; + testMessageNested = msg2; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorReasonNested, "database error"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "nested error!"); +} + +function testNestedOnFailWithErrorBPWithErrorArgsHavingBP() { + retry(3) { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + retry(3) { + fail error SampleComplexError("nested error!", cause = error("Database Error"), code = 30, pos = [35, 45], infoDetails = {moreInfo: "deadlock condition"}); + } on fail SampleComplexError error(_, cause = error(msg2), code = errCode2, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testMessage = msg1; + testMessageNested = msg2; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "Database Error"); + assertEquality(testErrorPosRow, 35); + assertEquality(testErrorPosCol, 45); +} + +function testMultiLevelOnFailWithErrorBP() { + int i = 2; + string str = ""; + + while i <= 2 { + retry(3) { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2 -> On Fail Final", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + int i = 2; + string str = ""; + + while i <= 2 { + retry(3) { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 2, -> On Fail #2", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + const ASSERTION_ERROR_REASON = "AssertionError"; function assertEquality(any|error expected, any|error actual) { diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative-reachability.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative-reachability.bal new file mode 100644 index 000000000000..7505d5d1d78c --- /dev/null +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative-reachability.bal @@ -0,0 +1,114 @@ +type ErrorTypeA distinct error; + +const TYPE_A_ERROR_REASON = "TypeA_Error"; + +type ErrorTypeB distinct error; + +const TYPE_B_ERROR_REASON = "TypeB_Error"; + +function testUnreachableAfterFail (int i) returns string { + string str = ""; + int count = i; + while (count < 5) { + count += 1; + error err = error("custom error", message = "error value"); + str += "Before failure throw"; + fail err; + str += "After failure throw"; + } + on fail error e { + str += "-> Error caught ! "; + } + str += "-> Execution continues..."; + return str; +} + +function testIncompatibleErrorTypeOnFail (int i) returns string { + string str = ""; + int count = i; + while (count < 5) { + count += 1; + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + } + str += "-> Execution continues..."; + return str; +} + +function testIgnoreReturnInOnFail (int i) returns string { + string str = ""; + int count = i; + while (count < 5) { + count += 1; + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + } + str += "-> Execution continues..."; + return str; +} + +function testUnreachableInOnFail (int i) returns string { + string str = ""; + int count = i; + while (count < 5) { + count += 1; + str += "Before failure throw"; + fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + } + on fail ErrorTypeA e { + str += "-> Error caught ! "; + return str; + str += "-> After returning string"; + } + str += "-> Execution continues..."; + return str; +} + +function testReturnWitihinDo(int i) returns string { + string str = ""; + int count = i; + while (count < 5) { + count += 1; + str = str + "do statement start"; + return str; + } + str = str + "do statemtnt finished"; +} + +function testOnFailWithUnion (int i) returns string { + string str = ""; + var getTypeAError = function () returns int|ErrorTypeA{ + ErrorTypeA errorA = error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); + return errorA; + }; + int count = i; + while (count < 5) { + count += 1; + str += "Before failure throw"; + int _ = check getTypeAError(); + } + on fail ErrorTypeA e { + str += "-> Error caught : "; + str = str.concat(e.message()); + } + str += "-> Execution continues..."; + return str; +} + +function testErrroDuplication() returns error? { + string str = ""; + int i = 3; + while (i > 2) { + i -= 1; + fail error("Custom Error"); + str += "-> unreachable"; + } + str += "-> unreachable"; +} diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative.bal index 772c3a04accb..cff4f22915dd 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail-negative.bal @@ -6,23 +6,6 @@ type ErrorTypeB distinct error; const TYPE_B_ERROR_REASON = "TypeB_Error"; -function testUnreachableAfterFail (int i) returns string { - string str = ""; - int count = i; - while (count < 5) { - count += 1; - error err = error("custom error", message = "error value"); - str += "Before failure throw"; - fail err; - str += "After failure throw"; - } - on fail error e { - str += "-> Error caught ! "; - } - str += "-> Execution continues..."; - return str; -} - function testIncompatibleErrorTypeOnFail (int i) returns string { string str = ""; int count = i; @@ -38,50 +21,6 @@ function testIncompatibleErrorTypeOnFail (int i) returns string { return str; } -function testIgnoreReturnInOnFail (int i) returns string { - string str = ""; - int count = i; - while (count < 5) { - count += 1; - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - } - str += "-> Execution continues..."; - return str; -} - -function testUnreachableInOnFail (int i) returns string { - string str = ""; - int count = i; - while (count < 5) { - count += 1; - str += "Before failure throw"; - fail error ErrorTypeA(TYPE_A_ERROR_REASON, message = "Error Type A"); - } - on fail ErrorTypeA e { - str += "-> Error caught ! "; - return str; - str += "-> After returning string"; - } - str += "-> Execution continues..."; - return str; -} - -function testReturnWitihinDo(int i) returns string { - string str = ""; - int count = i; - while (count < 5) { - count += 1; - str = str + "do statement start"; - return str; - } - str = str + "do statemtnt finished"; -} - function testOnFailWithUnion (int i) returns string { string str = ""; var getTypeAError = function () returns int|ErrorTypeA{ @@ -107,13 +46,29 @@ function testOnFailWithUnion (int i) returns string { return str; } -function testErrroDuplication() returns error? { - string str = ""; - int i = 3; - while (i > 2) { - i -= 1; - fail error("Custom Error"); - str += "-> unreachable"; +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +type SampleComplexErrorData record {| + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; +int whileIndex = 0; + +function testOnFailWithMultipleErrors() { + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + fail error SampleError("Transaction Failure", code = 50, reason = "deadlock condition"); + } on fail var error(msg) { } - str += "-> unreachable"; } diff --git a/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail.bal b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail.bal index ef242e00c801..05318a157e4f 100644 --- a/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail.bal +++ b/tests/jballerina-unit-test/src/test/resources/test-src/statements/whilestatement/while-stmt-on-fail.bal @@ -135,6 +135,490 @@ function testWhileStmtWithOnFailWithoutVariable() { assertEquality(" Value: 1 Value: 2 Value: 3-> error caught. -> reached end", str); } +type SampleErrorData record {| + int code; + string reason; +|}; + +type SampleError error; + +string testMessage = ""; +int testErrorCode = 0; +string testErrorReason = ""; +int whileIndex = 0; + +function testSimpleOnFailWithErrorBP() { + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error("error!"); + } + } on fail error error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testSimpleOnFailWithErrorBPWithVar() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error("error!"); + } + } on fail var error(msg) { + testMessage = msg; + } + assertEquality(testMessage, "error!"); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithError() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithVar() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedType() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail SampleError error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail1() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(msg, code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + testMessage = msg; + } + assertEquality(testMessage, "error!"); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail2() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail3() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode, reason = errReason) { + testErrorCode = errCode; + testErrorReason = errReason; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); +} + +function testOnFailWithErrorBPHavingUserDefinedTypeWithErrDetail4() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecord() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithVar() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail var error(msg, code = errCode) { + testErrorCode = errCode; + testErrorReason = msg; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); + assertEquality(testErrorReason is string, true); + assertEquality(testErrorReason, "error"); +} + +function testOnFailWithErrorBPHavingAnonDetailRecordWithUnionType() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + error errVar = error("error", code = 34); + fail errVar; + } + } on fail error error(code = errCode) { + testErrorCode = errCode; + } + assertEquality(testErrorCode, 34); + assertEquality(testErrorCode is int, true); +} + +type SampleComplexErrorData record {| + error cause; + int code; + int[2] pos; + record {string moreInfo;} infoDetails; +|}; + +type SampleComplexError error; + +int testErrorPosRow = 0; +int testErrorPosCol = 0; +string testErrorMoreInfo = ""; + + +function testOnFailWithErrorBPWithErrorArgsHavingBP1() { + string causeMsg = ""; + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(_, cause = errCause, code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + causeMsg = errCause.message(); + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(causeMsg, "Database Error"); + assertEquality(causeMsg is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP2() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = errorPos, infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = errorPos[0]; + testErrorPosCol = errorPos[1]; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP3() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(message, cause = error(msg), code = errCode, pos = [row, col], infoDetails = errInfo) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo.moreInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP4() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +function testOnFailWithErrorBPWithErrorArgsHavingBP5() { + whileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleComplexError("Transaction Failure", cause = error("Database Error"), code = 20, pos = [30, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail var error(_, cause = error(msg), code = errCode, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + testMessage = msg; + } + assertEquality(testErrorPosRow, 30); + assertEquality(testErrorPosRow is int, true); + assertEquality(testErrorPosCol, 45); + assertEquality(testErrorPosCol is int, true); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testErrorMoreInfo is string, true); + assertEquality(testErrorCode, 20); + assertEquality(testErrorCode is int, true); + assertEquality(testMessage, "Database Error"); + assertEquality(testMessage is string, true); +} + +int testErrorCodeNested = 0; +string testMessageNested = ""; + +function testNestedOnFailWithErrorBP() { + string testErrorReasonNested = ""; + whileIndex = 0; + int innerWhileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + while innerWhileIndex >= 0 { + innerWhileIndex = innerWhileIndex + 1; + if innerWhileIndex == 1 { + fail error SampleError("nested error!", code = 30, reason = "database error"); + } + } on fail var error(msg2, code = errCode2, reason = errReason2) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testErrorReason = errReason1; + testErrorReasonNested = errReason2; + testMessage = msg1; + testMessageNested = msg2; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testErrorReasonNested, "database error"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "nested error!"); +} + +function testNestedOnFailWithErrorBPWithErrorArgsHavingBP() { + whileIndex = 0; + int innerWhileIndex = 0; + while whileIndex >= 0 { + whileIndex = whileIndex + 1; + if whileIndex == 1 { + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + if errCode1 == 20 { + while innerWhileIndex >= 0 { + innerWhileIndex = innerWhileIndex + 1; + if innerWhileIndex == 1 { + fail error SampleComplexError("nested error!", cause = error("Database Error"), code = 30, pos = [35, 45], infoDetails = {moreInfo: "deadlock condition"}); + } + } on fail SampleComplexError error(_, cause = error(msg2), code = errCode2, pos = [row, col], infoDetails = {moreInfo: errInfo}) { + testErrorCode = errCode1; + testErrorCodeNested = errCode2; + testMessage = msg1; + testMessageNested = msg2; + testErrorPosRow = row; + testErrorPosCol = col; + testErrorMoreInfo = errInfo; + } + } + } + + assertEquality(testErrorCode, 20); + assertEquality(testErrorCodeNested, 30); + assertEquality(testErrorMoreInfo, "deadlock condition"); + assertEquality(testMessage, "error!"); + assertEquality(testMessageNested, "Database Error"); + assertEquality(testErrorPosRow, 35); + assertEquality(testErrorPosCol, 45); +} + +function testMultiLevelOnFailWithErrorBP() { + int i = 0; + string str = ""; + whileIndex = 0; + + while i == 0 { + while whileIndex == 0 { + whileIndex = whileIndex + 1; + if (whileIndex == 1) { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 0, -> On Fail #0 -> On Fail Final", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + +function testMultiLevelOnFailWithoutErrorInOneLevel() { + int i = 0; + string str = ""; + whileIndex = 0; + + while i == 0 { + while whileIndex == 0 { + whileIndex = whileIndex + 1; + if (whileIndex == 1) { + str += " -> Iteration " + i.toString() + ", "; + fail error SampleError("error!", code = 20, reason = "deadlock condition"); + } + } on fail var error(msg1, code = errCode1, reason = errReason1) { + str += " -> On Fail #" + i.toString(); + testMessage = msg1; + testErrorCode = errCode1; + testErrorReason = errReason1; + } + i = i + 1; + } on fail SampleError error(msg2, code = errCode2, reason = errReason2) { + str += " -> On Fail Final"; + } + + assertEquality(" -> Iteration 0, -> On Fail #0", str); + assertEquality(testErrorCode, 20); + assertEquality(testErrorReason, "deadlock condition"); + assertEquality(testMessage, "error!"); +} + function assertEquality(anydata expected, anydata actual) { if actual == expected { return;