Skip to content

Commit

Permalink
Add compiler plugin tests
Browse files Browse the repository at this point in the history
  • Loading branch information
LakshanWeerasinghe committed Jun 7, 2024
1 parent 7123aac commit 15de097
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@ public void testDuplicateField2() {
"invalid field: duplicate field found");
}

@Test
public void testDuplicateFieldInUnion() {
DiagnosticResult diagnosticResult =
CompilerPluginTestUtils.loadPackage("sample_package_9").getCompilation().diagnosticResult();
List<Diagnostic> errorDiagnosticsList = diagnosticResult.diagnostics().stream()
.filter(r -> r.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)).toList();
Assert.assertEquals(errorDiagnosticsList.size(), 2);
Assert.assertEquals(errorDiagnosticsList.get(0).diagnosticInfo().messageFormat(),
"invalid field: duplicate field found");
Assert.assertEquals(errorDiagnosticsList.get(1).diagnosticInfo().messageFormat(),
"invalid field: duplicate field found");
}

@Test
public void testComplexUnionTypeAsExpectedType() {
DiagnosticResult diagnosticResult =
Expand All @@ -119,4 +132,18 @@ public void testComplexUnionTypeAsMemberOfIntersection() {
Assert.assertEquals(errorDiagnosticsList.size(), 1);
Assert.assertEquals(errorDiagnosticsList.get(0).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE);
}

@Test
public void testComplexUnionTypeWithUnsupportedTypeAndDuplicateFields() {
DiagnosticResult diagnosticResult =
CompilerPluginTestUtils.loadPackage("sample_package_10").getCompilation().diagnosticResult();
List<Diagnostic> errorDiagnosticsList = diagnosticResult.diagnostics().stream()
.filter(r -> r.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)).toList();
Assert.assertEquals(errorDiagnosticsList.size(), 3);
Assert.assertEquals(errorDiagnosticsList.get(0).diagnosticInfo().messageFormat(),
"invalid field: duplicate field found");
Assert.assertEquals(errorDiagnosticsList.get(1).diagnosticInfo().messageFormat(),
"invalid field: duplicate field found");
Assert.assertEquals(errorDiagnosticsList.get(2).diagnosticInfo().messageFormat(), UNSUPPORTED_TYPE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "yamldata_test"
name = "sample_10"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
//
// WSO2 LLC. 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.

import ballerina/data.yaml;

type ArrayExpectedType record {|
@yaml:Name {
value: "first_name"
}
string firstName;

@yaml:Name {
value: "first_name"
}
string lastName;
|}[];

type TupleExpectedType [record {|
@yaml:Name {
value: "first_name"
}
string firstName;

@yaml:Name {
value: "first_name"
}
string lastName;
|}];

type ImmutableType readonly & ArrayExpectedType;

type UnionType ArrayExpectedType|TupleExpectedType|ImmutableType|xml|table<record{}>;

function call(string data) returns error? {
UnionType result = check yaml:parseString(data);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "yamldata_test"
name = "sample_9"
version = "0.1.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
//
// WSO2 LLC. 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.

import ballerina/data.yaml;

type ArrayExpectedType record {|
@yaml:Name {
value: "first_name"
}
string firstName;

@yaml:Name {
value: "first_name"
}
string lastName;
|}[];

type TupleExpectedType [record {|
@yaml:Name {
value: "first_name"
}
string firstName;

@yaml:Name {
value: "first_name"
}
string lastName;
|}];

type ImmutableType readonly & ArrayExpectedType;

type UnionType ArrayExpectedType|TupleExpectedType|ImmutableType;

function call() returns UnionType {
UnionType callResult = call();

return <ArrayExpectedType>[{
firstName: "",
lastName: ""
}];
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import io.ballerina.compiler.syntax.tree.ModuleVariableDeclarationNode;
import io.ballerina.compiler.syntax.tree.NameReferenceNode;
import io.ballerina.compiler.syntax.tree.Node;
import io.ballerina.compiler.syntax.tree.NodeList;
import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode;
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.compiler.syntax.tree.TypeDefinitionNode;
Expand Down Expand Up @@ -103,7 +104,9 @@ public void perform(SyntaxNodeAnalysisContext ctx) {
}
}

for (ModuleMemberDeclarationNode member : rootNode.members()) {
NodeList<ModuleMemberDeclarationNode> members = rootNode.members();
for (int i = 0; i < members.size(); i++) {
ModuleMemberDeclarationNode member = members.get(i);
switch (member.kind()) {
case FUNCTION_DEFINITION -> processFunctionDefinitionNode((FunctionDefinitionNode) member, ctx);
case MODULE_VAR_DECL ->
Expand Down Expand Up @@ -187,7 +190,7 @@ private boolean isParseFunctionOfStringSource(ExpressionNode expressionNode) {
private void validateExpectedType(TypeSymbol typeSymbol, SyntaxNodeAnalysisContext ctx) {
typeSymbol.getLocation().ifPresent(location -> currentLocation = location);
switch (typeSymbol.typeKind()) {
case UNION -> validateUnionType((UnionTypeSymbol) typeSymbol, typeSymbol.getLocation(), ctx);
case UNION -> validateUnionType((UnionTypeSymbol) typeSymbol, ctx);
case RECORD -> validateRecordType((RecordTypeSymbol) typeSymbol, ctx);
case ARRAY -> validateExpectedType(((ArrayTypeSymbol) typeSymbol).memberTypeDescriptor(), ctx);
case TUPLE -> validateTupleType((TupleTypeSymbol) typeSymbol, ctx);
Expand Down Expand Up @@ -215,35 +218,11 @@ private void validateRecordType(RecordTypeSymbol recordTypeSymbol, SyntaxNodeAna
}
}

private void validateUnionType(UnionTypeSymbol unionTypeSymbol, Optional<Location> location,
private void validateUnionType(UnionTypeSymbol unionTypeSymbol,
SyntaxNodeAnalysisContext ctx) {
boolean isHasUnsupportedType = false;
List<TypeSymbol> memberTypeSymbols = unionTypeSymbol.memberTypeDescriptors();
for (TypeSymbol memberTypeSymbol : memberTypeSymbols) {
if (isSupportedUnionMemberType(getRawType(memberTypeSymbol))) {
continue;
}
isHasUnsupportedType = true;
}

if (isHasUnsupportedType) {
reportDiagnosticInfo(ctx, location, YamlDataDiagnosticCodes.UNSUPPORTED_TYPE);
}
}

private boolean isSupportedUnionMemberType(TypeSymbol typeSymbol) {
TypeDescKind kind = typeSymbol.typeKind();
if (kind == TypeDescKind.TYPE_REFERENCE) {
kind = ((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor().typeKind();
}

switch (kind) {
case TABLE, XML -> {
return false;
}
default -> {
return true;
}
validateExpectedType(getRawType(memberTypeSymbol), ctx);
}
}

Expand Down Expand Up @@ -342,16 +321,11 @@ private String getNameFromAnnotation(String fieldName,
}

private String getAnnotModuleName(AnnotationSymbol annotation) {
Optional<ModuleSymbol> moduleSymbol = annotation.getModule();
if (moduleSymbol.isEmpty()) {
return "";
}
Optional<String> moduleName = moduleSymbol.get().getName();
return moduleName.orElse("");
return annotation.getModule().flatMap(Symbol::getName).orElse("");
}

public static boolean isYamlImport(ModuleSymbol moduleSymbol) {
return BALLERINA.equals(moduleSymbol.id().orgName())
return BALLERINA.equals(moduleSymbol.id().orgName())
&& DATA_YAML.equals(moduleSymbol.id().moduleName());
}
}

0 comments on commit 15de097

Please sign in to comment.