/*
 * $Id$
 *
 * SARL is an general-purpose agent programming language.
 * More details on http://www.sarl.io
 *
 * Copyright (C) 2014-2026 SARL.io, the original authors and main authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.sarl.lang.tests.general.parsing.aop;

import static io.sarl.lang.tests.api.tools.TestAssertions.assertParameterDefaultValues;
import static io.sarl.lang.validation.IssueCodes.DUPLICATE_TYPE_NAME;
import static io.sarl.tests.api.tools.TestAssertions.assertNullOrEmpty;
import static io.sarl.tests.api.tools.TestAssertions.assertParameterNames;
import static io.sarl.tests.api.tools.TestAssertions.assertParameterTypes;
import static io.sarl.tests.api.tools.TestAssertions.assertTypeReferenceIdentifier;
import static io.sarl.tests.api.tools.TestAssertions.assertXExpression;
import static io.sarl.tests.api.tools.TestEObjects.file;
import static io.sarl.tests.api.tools.TestUtils.multilineString;
import static io.sarl.tests.api.tools.TestValidator.validate;
import static org.eclipse.xtend.core.validation.IssueCodes.FIELD_NOT_INITIALIZED;
import static org.eclipse.xtend.core.validation.IssueCodes.INVALID_MEMBER_NAME;
import static org.eclipse.xtend.core.validation.IssueCodes.INVALID_MODIFIER;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_ABSTRACT;
import static org.eclipse.xtend.core.validation.IssueCodes.MISSING_OVERRIDE;
import static org.eclipse.xtend.core.validation.IssueCodes.OBSOLETE_OVERRIDE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.CLASS_EXPECTED;
import static org.eclipse.xtext.xbase.validation.IssueCodes.CYCLIC_INHERITANCE;
import static org.eclipse.xtext.xbase.validation.IssueCodes.DUPLICATE_FIELD;
import static org.eclipse.xtext.xbase.validation.IssueCodes.DUPLICATE_METHOD;
import static org.eclipse.xtext.xbase.validation.IssueCodes.MUST_INVOKE_SUPER_CONSTRUCTOR;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.google.common.base.Strings;
import org.eclipse.xtext.common.types.JvmTypeConstraint;
import org.eclipse.xtext.common.types.JvmTypeParameter;
import org.eclipse.xtext.common.types.JvmVisibility;
import org.eclipse.xtext.xbase.XNumberLiteral;
import org.eclipse.xtext.xbase.XStringLiteral;
import org.eclipse.xtext.xbase.XbasePackage;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import io.sarl.lang.sarl.SarlAction;
import io.sarl.lang.sarl.SarlBehavior;
import io.sarl.lang.sarl.SarlConstructor;
import io.sarl.lang.sarl.SarlField;
import io.sarl.lang.sarl.SarlPackage;
import io.sarl.lang.sarl.SarlScript;
import io.sarl.lang.tests.api.AbstractSarlTest;
import io.sarl.lang.validation.IssueCodes;

/**
 * @author $Author: sgalland$
 * @version $Name$ $Revision$ $Date$
 * @mavengroupid $GroupId$
 * @mavenartifactid $ArtifactId$
 */
@SuppressWarnings("all")
@DisplayName("Syntax: behavior")
@Tag("core")
public class BehaviorParsingTest {

	@Nested
	public class TopElementTest extends AbstractSarlTest {

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_0() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"capacity C1 {",
				"}",
				"behavior B1 extends C1 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				CLASS_EXPECTED,
				"Invalid supertype. Expecting a class");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_1() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"agent A1 {",
				"}",
				"behavior B3 extends A1 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				IssueCodes.INVALID_EXTENDED_TYPE,
				"Supertype must be of type 'io.sarl.lang.core.Behavior'");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_2() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 extends B1 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				CYCLIC_INHERITANCE,
				"The inheritance hierarchy of B1 contains cycles");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_3() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 extends B2 {",
				"}",
				"behavior B2 extends B1 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				IssueCodes.INVALID_EXTENDED_TYPE,
				"Supertype must be of type 'io.sarl.lang.core.Behavior'");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_4() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 extends B2 {",
				"}",
				"behavior B2 extends B1 {",
				"}",
				"behavior B3 extends B2 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				IssueCodes.INVALID_EXTENDED_TYPE,
				"Supertype must be of type 'io.sarl.lang.core.Behavior'");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidExtend_5() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B3 extends B2 {",
				"}",
				"behavior B2 extends B1 {",
				"}",
				"behavior B1 extends B2 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				IssueCodes.INVALID_EXTENDED_TYPE,
				"Supertype must be of type 'io.sarl.lang.core.Behavior'");
		}

		@Test
		@Tag("sarlValidation")
		public void duplicateTypeNames() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"package io.sarl.test",
				"behavior B1 {",
				"}",
				"behavior B2 {",
				"}",
				"behavior B1 {",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlBehavior(),
				DUPLICATE_TYPE_NAME,
				"Duplicate type B1");
		}

		@Test
		@Tag("sarlParsing")
		public void behaviormodifier_public() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"public behavior B1 {}"
					));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(0, beh.getMembers().size());
			assertFalse(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void behaviormodifier_none() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {}"
					));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(0, beh.getMembers().size());
			assertFalse(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_private() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"private behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_protected() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"protected behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlParsing")
		public void behaviormodifier_package() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"package behavior B1 {}"
					));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.DEFAULT, beh.getVisibility());
			assertEquals(0, beh.getMembers().size());
			assertFalse(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void behaviormodifier_abstract() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {}"
					));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(0, beh.getMembers().size());
			assertTrue(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_static() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"static behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_dispatch() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"dispatch behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlParsing")
		public void behaviormodifier_final() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"final behavior B1 {}"
					));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(0, beh.getMembers().size());
			assertFalse(beh.isAbstract());
			assertTrue(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_strictfp() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"strictfp behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_native() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"native behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_volatile() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"volatile behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_synchronized() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"synchronized behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_transient() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"transient behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER);
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_abstract_final() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract final behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER,
					"The definition of B1 can either be abstract or final, not both");
		}

		@Test
		@Tag("sarlValidation")
		public void modifier_abstract_action_error_0() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	def name",
					"}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlAction(),
					MISSING_ABSTRACT);
		}

		@Test
		@Tag("sarlValidation")
		public void modifier_abstract_action_error_1() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	abstract def name",
					"}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlAction(),
					MISSING_ABSTRACT);
		}
		
		@Test
		@Tag("sarlParsing")
		public void modifier_abstract_action_warning() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	def name",
					"}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertWarning(
					SarlPackage.eINSTANCE.getSarlAction(),
					MISSING_ABSTRACT);
			//
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(1, beh.getMembers().size());
			assertTrue(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_abstract_action() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	abstract def name",
					"}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertNoIssues();
			//
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(JvmVisibility.PUBLIC, beh.getVisibility());
			assertEquals(1, beh.getMembers().size());
			assertTrue(beh.isAbstract());
			assertFalse(beh.isFinal());
			assertFalse(beh.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlValidation")
		public void behaviormodifier_public_package() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"public package behavior B1 {}"
					));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlBehavior(),
					INVALID_MODIFIER,
					"The definition of B1 can only set one of public, package, abstract or final");
		}

	}

	@Nested
	public class ActionTest extends AbstractSarlTest {

		@Test
		@Tag("sarlValidation")
		public void modifier_override_notRecommended() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	abstract def name",
					"}",
					"behavior B2 extends B1 {",
					"	def name { }",
					"}"));
			validate(getValidationHelper(), getInjector(), mas).assertNoWarnings(
					SarlPackage.eINSTANCE.getSarlAction(),
					MISSING_OVERRIDE);
		}

		@Test
		@Tag("sarlValidation")
		public void modifier_override_invalid() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"}",
					"behavior B2 extends B1 {",
					"	override name { }",
					"}"));
			validate(getValidationHelper(), getInjector(), mas).assertError(
					SarlPackage.eINSTANCE.getSarlAction(),
					OBSOLETE_OVERRIDE,
					"The method name() of type B2 must override a superclass method");
		}

		@Test
		@Tag("sarlValidation")
		public void modifier_override_valid() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	abstract def name",
					"}",
					"behavior B2 extends B1 {",
					"	override name { }",
					"}"));
			validate(getValidationHelper(), getInjector(), mas).assertNoIssues();
		}

		@Test
		@Tag("sarlValidation")
		public void multipleActionDefinition() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int, b : int) { }",
				"	def myaction(a : int) { }",
				"	def myaction(a : int) { }",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlAction(),
				DUPLICATE_METHOD,
				"Duplicate method myaction(int) in type B1");
		}

		@Test
		@Tag("sarlValidation")
		public void invalidActionName() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction {",
				"		System.out.println(\"ok\")",
				"	}",
				"	def $handle_myaction {",
				"		System.out.println(\"ko\")",
				"	}",
				"	def myaction2 {",
				"		System.out.println(\"ok\")",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlAction(),
				INVALID_MEMBER_NAME,
				"Invalid action name '$handle_myaction'.");
		}

		@Test
		@Tag("sarlValidation")
		public void incompatibleReturnType_0() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) : int {",
				"		return 0",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) : float {",
				"		return 0f",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlAction(),
				org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_RETURN_TYPE);
		}

		@Test
		@Tag("sarlValidation")
		public void incompatibleReturnType_1() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) {",
				"		// void",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) : int {",
				"		return 0",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlAction(),
				org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_RETURN_TYPE);
		}

		@Test
		@Tag("sarlValidation")
		public void incompatibleReturnType_2() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) : int {",
				"		return 0",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) : void {",
				"		// void",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlAction(),
				org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_RETURN_TYPE);
		}

		@Test
		@Tag("sarlValidation")
		public void incompatibleReturnType_3() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) : int {",
				"		return 0",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) {",
				"		// int return type is inferred",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				XbasePackage.eINSTANCE.getXBlockExpression(),
				org.eclipse.xtext.xbase.validation.IssueCodes.INCOMPATIBLE_TYPES,
				"Type mismatch: cannot convert from null to int");
		}

		@Test
		@Tag("sarlParsing")
		public void compatibleReturnType_0() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) : Number {",
				"		return 0.0",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) : Double {",
				"		return 0.0",
				"	}",
				"}"
			));
			assertEquals(2, mas.getXtendTypes().size());
			//
			assertTrue(Strings.isNullOrEmpty(mas.getPackage()));
			//
			SarlBehavior behavior1 = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", behavior1.getName());
			assertNull(behavior1.getExtends());
			assertEquals(1, behavior1.getMembers().size());
			//
			SarlAction action1 = (SarlAction) behavior1.getMembers().get(0);
			assertEquals("myaction", action1.getName());
			assertTrue(action1.getFiredEvents().isEmpty());
			assertTypeReferenceIdentifier(action1.getReturnType(), "java.lang.Number");
			assertParameterNames(action1.getParameters(), "a");
			assertParameterTypes(action1.getParameters(), "int");
			assertParameterDefaultValues(action1.getParameters(), (Object) null);
			//
			SarlBehavior behavior2= (SarlBehavior) mas.getXtendTypes().get(1);
			assertEquals("B2", behavior2.getName());
			assertTypeReferenceIdentifier(behavior2.getExtends(), "B1");
			assertEquals(1, behavior2.getMembers().size());
			//
			SarlAction action2 = (SarlAction) behavior2.getMembers().get(0);
			assertEquals("myaction", action2.getName());
			assertTrue(action2.getFiredEvents().isEmpty());
			assertTypeReferenceIdentifier(action2.getReturnType(), "java.lang.Double");
			assertParameterNames(action2.getParameters(), "a");
			assertParameterTypes(action2.getParameters(), "int");
			assertParameterDefaultValues(action2.getParameters(), (Object) null);
		}

		@Test
		@Tag("sarlParsing")
		public void compatibleReturnType_1() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int) : float {",
				"		return 0f",
				"	}",
				"}",
				"behavior B2 extends B1 {",
				"	def myaction(a : int) : float {",
				"		return 0f",
				"	}",
				"}"
			));
			assertEquals(2, mas.getXtendTypes().size());
			//
			assertTrue(Strings.isNullOrEmpty(mas.getPackage()));
			//
			SarlBehavior behavior1 = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", behavior1.getName());
			assertNull(behavior1.getExtends());
			assertEquals(1, behavior1.getMembers().size());
			//
			SarlAction action1 = (SarlAction) behavior1.getMembers().get(0);
			assertEquals("myaction", action1.getName());
			assertTrue(action1.getFiredEvents().isEmpty());
			assertTypeReferenceIdentifier(action1.getReturnType(), "float");
			assertParameterNames(action1.getParameters(), "a");
			assertParameterTypes(action1.getParameters(), "int");
			assertParameterDefaultValues(action1.getParameters(), (Object) null);
			//
			SarlBehavior behavior2= (SarlBehavior) mas.getXtendTypes().get(1);
			assertEquals("B2", behavior2.getName());
			assertTypeReferenceIdentifier(behavior2.getExtends(), "B1");
			assertEquals(1, behavior2.getMembers().size());
			//
			SarlAction action2 = (SarlAction) behavior2.getMembers().get(0);
			assertEquals("myaction", action2.getName());
			assertTrue(action2.getFiredEvents().isEmpty());
			assertTypeReferenceIdentifier(action2.getReturnType(), "float");
			assertParameterNames(action2.getParameters(), "a");
			assertParameterTypes(action2.getParameters(), "int");
			assertParameterDefaultValues(action2.getParameters(), (Object) null);
		}

		@Test
		@Tag("sarlValidation")
		public void multipleParameterNames() throws Exception {
			SarlScript mas = file(getParseHelper(), multilineString(
				"behavior B1 {",
				"	def myaction(a : int, b : int, c : int, b : int) {",
				"	}",
				"}"
			));
			validate(getValidationHelper(), getInjector(), mas).assertError(
				SarlPackage.eINSTANCE.getSarlFormalParameter(),
				org.eclipse.xtext.xbase.validation.IssueCodes.VARIABLE_NAME_SHADOWING,
				"Duplicate local variable b");
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_public() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	public def name { }",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.PUBLIC, act1.getVisibility());
			assertFalse(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_private() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	private def name { }",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.PRIVATE, act1.getVisibility());
			assertFalse(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_protected() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	protected def name { }",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.PROTECTED, act1.getVisibility());
			assertFalse(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_package() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	package def name { }",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.DEFAULT, act1.getVisibility());
			assertFalse(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_none() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"behavior B1 {",
					"	def name { }",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.PUBLIC, act1.getVisibility());
			assertFalse(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_abstract() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	abstract def name",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
			SarlAction act1 = (SarlAction) beh.getMembers().get(0);
			assertEquals("name", act1.getName());
			assertEquals(JvmVisibility.PUBLIC, act1.getVisibility());
			assertTrue(act1.isAbstract());
			assertFalse(act1.isStatic());
			assertFalse(act1.isDispatch());
			assertFalse(act1.isFinal());
			assertFalse(act1.isSynchonized());
			assertFalse(act1.isStrictFloatingPoint());
		}

		@Test
		@Tag("sarlParsing")
		public void modifier_no_abstract() throws Exception {
			SarlScript mas = file(getParseHelper(), getValidationHelper(), multilineString(
					"package io.sarl.lang.tests.test",
					"abstract behavior B1 {",
					"	def name",
					"}"));
			assertEquals(1, mas.getXtendTypes().size());
			//
			assertEquals("io.sarl.lang.tests.test", mas.getPackage());
			//
			SarlBehavior beh = (SarlBehavior) mas.getXtendTypes().get(0);
			assertEquals("B1", beh.getName());
			assertNull(beh.getExtends());
			assertEquals(1, beh.getMembers().size());
			//
