| /******************************************************************************* |
| * Copyright (c) 2006, 2013 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| * E.D.Willink - Bug 296409, 297541 |
| *******************************************************************************/ |
| |
| package org.eclipse.ocl.examples.pivot.tests; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EFactory; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.plugin.EcorePlugin; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.ocl.examples.domain.ids.CollectionTypeId; |
| import org.eclipse.ocl.examples.domain.ids.TypeId; |
| import org.eclipse.ocl.examples.domain.messages.EvaluatorMessages; |
| import org.eclipse.ocl.examples.domain.utilities.DomainUtil; |
| import org.eclipse.ocl.examples.domain.values.BagValue; |
| import org.eclipse.ocl.examples.domain.values.CollectionValue; |
| import org.eclipse.ocl.examples.domain.values.OrderedSetValue; |
| import org.eclipse.ocl.examples.domain.values.SequenceValue; |
| import org.eclipse.ocl.examples.domain.values.SetValue; |
| import org.eclipse.ocl.examples.domain.values.Value; |
| import org.eclipse.ocl.examples.domain.values.impl.InvalidValueException; |
| import org.eclipse.ocl.examples.domain.values.util.ValuesUtil; |
| import org.eclipse.ocl.examples.library.LibraryConstants; |
| import org.eclipse.ocl.examples.pivot.Operation; |
| import org.eclipse.ocl.examples.pivot.PivotTables; |
| import org.eclipse.ocl.examples.pivot.Property; |
| import org.eclipse.ocl.examples.pivot.Root; |
| import org.eclipse.ocl.examples.pivot.SemanticException; |
| import org.eclipse.ocl.examples.pivot.Type; |
| import org.eclipse.ocl.examples.pivot.manager.MetaModelManager; |
| import org.eclipse.ocl.examples.pivot.messages.OCLMessages; |
| import org.eclipse.ocl.examples.xtext.oclinecore.OCLinEcoreStandaloneSetup; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| /** |
| * Tests for iterator expressions. |
| * |
| * @author Christian W. Damus (cdamus) |
| */ |
| @SuppressWarnings("nls") |
| @RunWith(value = Parameterized.class) |
| public class IteratorsTest4 extends PivotTestSuite |
| { |
| @Parameters |
| public static Collection<Object[]> data() { |
| Object[][] data = new Object[][]{{false}, {true}}; |
| return Arrays.asList(data); |
| } |
| |
| public IteratorsTest4(boolean useCodeGen) { |
| super(useCodeGen); |
| } |
| |
| Root root; |
| org.eclipse.ocl.examples.pivot.Package pkg1; |
| org.eclipse.ocl.examples.pivot.Package pkg2; |
| org.eclipse.ocl.examples.pivot.Package pkg3; |
| org.eclipse.ocl.examples.pivot.Package pkg4; |
| org.eclipse.ocl.examples.pivot.Package pkg5; |
| org.eclipse.ocl.examples.pivot.Package jim; |
| org.eclipse.ocl.examples.pivot.Package bob; |
| org.eclipse.ocl.examples.pivot.Package george; |
| |
| @Override |
| protected @NonNull String getTestPackageName() { |
| return "Iterators"; |
| } |
| |
| @BeforeClass public static void resetCounter() throws Exception { |
| PivotTestSuite.resetCounter(); |
| } |
| |
| @SuppressWarnings("null") |
| @Override |
| @Before public void setUp() throws Exception { |
| super.setUp(); |
| PivotTables.LIBRARY.getClass(); |
| // metaModelManager.addGlobalNamespace(PivotConstants.OCL_NAME, DomainUtil.nonNullState(metaModelManager.getASMetamodel())); |
| |
| // need a metamodel that has a reflexive EReference. |
| // Ecore will do nicely. Create the following structure: |
| // pkg1 |
| // pkg1::pkg2 |
| // pkg1::pkg2::jim |
| // pkg1::bob |
| // pkg1::pkg3 |
| // pkg1::pkg3::pkg4 |
| // pkg1::pkg3::pkg5 |
| // pkg1::pkg3::pkg5::george |
| |
| root = createRoot(); |
| pkg1 = createPackage(root, "pkg1"); |
| pkg2 = createPackage(pkg1, "pkg2"); |
| jim = createPackage(pkg2, "jim"); |
| bob = createPackage(pkg1, "bob"); |
| pkg3 = createPackage(pkg1, "pkg3"); |
| pkg4 = createPackage(pkg3, "pkg4"); |
| pkg5 = createPackage(pkg3, "pkg5"); |
| george = createPackage(pkg5, "george"); |
| metaModelManager.installRoot(DomainUtil.nonNullState(root)); |
| helper.setContext(DomainUtil.nonNullState(metaModelManager.getPivotType("Package"))); |
| } |
| |
| @Override |
| @After public void tearDown() throws Exception { |
| super.tearDown(); |
| } |
| |
| /** |
| * Tests the generic iterate() iterator. |
| */ |
| @Test public void test_iterate_143996() { |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(TypeId.STRING); |
| SetValue expected = idResolver.createSetOfEach(typeId, "pkg2", "bob", "pkg3"); |
| |
| // complete form |
| assertQueryEquals(pkg1, expected, "nestedPackage->iterate(p; s : Set(String) = Set{} | s->including(p.name))"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expected, "nestedPackage->iterate(p; s : Set(String) = Set{} | s->including(p.name))"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expected, "nestedPackage->iterate(s : Set(String) = Set{} | s->including(name))"); |
| |
| assertQueryEquals(pkg1, "pfx_a_b_c", "Sequence{'a','b','c'}->iterate(e : String; s : String = 'pfx' | s + '_' + e)"); |
| } |
| |
| /** |
| * Tests the select() iterator. |
| */ |
| @Test public void test_select() { |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(packageType.getTypeId()); |
| CollectionValue expected = idResolver.createSetOfEach(typeId, pkg2, pkg3); |
| |
| // complete form |
| assertQueryEquals(pkg1, expected, "nestedPackage->select(p : ocl::Package | p.name <> 'bob')"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expected, "nestedPackage->select(p | p.name <> 'bob')"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expected, "nestedPackage->select(name <> 'bob')"); |
| |
| Value expected2 = idResolver.createSetOfEach(typeId, bob, pkg2, pkg3); |
| assertQueryEquals(pkg1, expected2, "nestedPackage->select(true)"); |
| } |
| |
| /** |
| * Tests the reject() iterator. |
| */ |
| @Test public void test_reject() { |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(packageType.getTypeId()); |
| CollectionValue expected = idResolver.createSetOfEach(typeId, pkg2, pkg3); |
| |
| // complete form |
| assertQueryEquals(pkg1, expected, "nestedPackage->reject(p : ocl::Package | p.name = 'bob')"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expected, "nestedPackage->reject(p | p.name = 'bob')"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expected, "nestedPackage->reject(name = 'bob')"); |
| |
| expected = idResolver.createSetOfEach(typeId); |
| assertQueryEquals(pkg1, expected, "nestedPackage->reject(true)"); |
| } |
| |
| /** |
| * Tests the any() iterator. |
| */ |
| @Test public void test_any() { |
| // complete form |
| assertQueryEquals(pkg1, bob, "nestedPackage->any(p : ocl::Package | p.name = 'bob')"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, bob, "nestedPackage->any(p | p.name = 'bob')"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, bob, "nestedPackage->any(name = 'bob')"); |
| |
| // negative |
| assertQueryNotSame(pkg1, bob, "nestedPackage->any(name = 'pkg2')"); |
| |
| assertQueryInvalid(null, "Sequence{}->any(s | s = false)"); // OMG Issue 18504 |
| assertQueryFalse(null, "Sequence{false}->any(s | s = false)"); |
| assertQueryFalse(null, "Sequence{false, false}->any(s | s = false)"); |
| |
| assertQueryInvalid(null, "Sequence{}->any(s | s = null)"); // OMG Issue 18504 |
| assertQueryNull(null, "Sequence{null}->any(s | s = null)"); |
| assertQueryNull(null, "Sequence{null, null}->any(s | s = null)"); |
| |
| assertQueryDefined(pkg1, "nestedPackage->any(true)"); |
| assertQueryInvalid(pkg1, "nestedPackage->any(false)"); // OMG Issue 18504 |
| } |
| |
| /** |
| * Tests the isUnique() iterator. |
| */ |
| @Test public void test_isUnique_126861() { |
| // Abstract2Moniker.TRACE_MONIKERS.setState(true); |
| assertQueryTrue(pkg1, "Sequence{'a', 'b', 'c', 'd', 'e'}->isUnique(e | e)"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'c', 'c', 'e'}->isUnique(e | e)"); |
| |
| // when there are no values, they implicitly all evaluate to a |
| // different result |
| assertQueryTrue(pkg1, "Sequence{}->isUnique(e | e)"); |
| assertQueryTrue(pkg1, "Sequence{null}->isUnique(e | e)"); |
| assertQueryTrue(pkg1, "Sequence{null,1}->isUnique(e | e)"); |
| assertQueryFalse(pkg1, "Sequence{null,null}->isUnique(e | e)"); |
| |
| assertQueryTrue(pkg1, "nestedPackage->isUnique(name)"); |
| } |
| |
| /** |
| * Tests the exists() iterator. |
| */ |
| @Test public void test_exists() { |
| assertQueryFalse(null, "Sequence{Sequence{false}, Sequence{false}, Sequence{false}, Sequence{false}}->exists(e | e->first())"); |
| assertQueryTrue(null, "Sequence{Sequence{false}, Sequence{true}, Sequence{false}, Sequence{false}}->exists(e | e->first())"); |
| assertQueryTrue(null, "Sequence{Sequence{false}, Sequence{true}, Sequence{null}, Sequence{true}}->exists(e | e->first())"); |
| assertQueryNull(null, "Sequence{Sequence{false}, Sequence{false}, Sequence{null}, Sequence{false}}->exists(e | e->first())"); |
| assertQueryTrue(null, "Sequence{Sequence{false}, Sequence{true}, Sequence{null}, Sequence{}}->exists(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{false}, Sequence{false}, Sequence{null}, Sequence{}}->exists(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{false}, Sequence{false}, Sequence{}, Sequence{null}}->exists(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{false}, Sequence{false}, Sequence{false}, Sequence{}}->exists(e | e->first())"); |
| |
| assertQueryTrue(pkg1, "Sequence{'a', 'b', 'c', 'd', 'e'}->exists(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "Sequence{'a', 'b', 'c', 'c', 'e'}->exists(e | e = 'c')"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'd', 'e'}->exists(e | e = 'c')"); |
| |
| // when there are no values, they the desired result implictly |
| // does not occur |
| assertQueryFalse(pkg1, "Sequence{}->exists(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "nestedPackage->exists(true)"); |
| } |
| |
| /** |
| * Tests the forAll() iterator. |
| */ |
| @Test public void test_forAll() { |
| assertQueryTrue(null, "Sequence{Sequence{true}, Sequence{true}, Sequence{true}, Sequence{true}}->forAll(e | e->first())"); |
| assertQueryFalse(null, "Sequence{Sequence{true}, Sequence{false}, Sequence{true}, Sequence{true}}->forAll(e | e->first())"); |
| assertQueryFalse(null, "Sequence{Sequence{true}, Sequence{false}, Sequence{null}, Sequence{false}}->forAll(e | e->first())"); |
| assertQueryNull(null, "Sequence{Sequence{true}, Sequence{true}, Sequence{null}, Sequence{true}}->forAll(e | e->first())"); |
| assertQueryFalse(null, "Sequence{Sequence{true}, Sequence{false}, Sequence{null}, Sequence{}}->forAll(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{true}, Sequence{true}, Sequence{null}, Sequence{}}->forAll(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{true}, Sequence{true}, Sequence{}, Sequence{null}}->forAll(e | e->first())"); |
| assertQueryInvalid(null, "Sequence{Sequence{true}, Sequence{true}, Sequence{true}, Sequence{}}->forAll(e | e->first())"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'c', 'd', 'e'}->forAll(e | e = 'c')"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'd', 'e'}->forAll(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "Sequence{'c', 'c', 'c', 'c'}->forAll(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "Sequence{'c'}->forAll(e | e = 'c')"); |
| |
| // when there are no values, they implicitly all evaluate to the |
| // desired result |
| assertQueryTrue(pkg1, "Sequence{}->forAll(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "nestedPackage->forAll(true)"); |
| // |
| assertQueryTrue(pkg1, "Sequence{1..0}->forAll(false)"); |
| assertQueryFalse(pkg1, "Sequence{1..1}->forAll(false)"); |
| } |
| |
| /** |
| * Tests the one() iterator. |
| */ |
| @Test public void test_one() { |
| assertQueryTrue(pkg1, "Sequence{'a', 'b', 'c', 'd', 'e'}->one(e | e = 'c')"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'c', 'c', 'e'}->one(e | e = 'c')"); |
| |
| assertQueryFalse(pkg1, "Sequence{'a', 'b', 'd', 'e'}->one(e | e = 'c')"); |
| |
| assertQueryTrue(pkg1, "Sequence{'a'}->one(true)"); |
| } |
| |
| /** |
| * Tests the collect() iterator. |
| */ |
| @Test public void test_collect() { |
| // Abstract2Moniker.TRACE_MONIKERS.setState(true); |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.BAG.getSpecializedId(packageType.getTypeId()); |
| CollectionValue expected1 = idResolver.createBagOfEach(typeId, "pkg2", "bob", "pkg3"); |
| |
| // complete form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collect(p : ocl::Package | p.name)"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collect(p | p.name)"); |
| |
| // yet shorter form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collect(name)"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expected1, "nestedPackage.name"); |
| |
| // flattening of nested collections |
| CollectionValue expected2 = idResolver.createBagOfEach(typeId, jim, pkg4, pkg5); |
| // nestedPackage is Set<Package> |
| // nestedPackage->collectNested(nestedPackage) is Bag<Set<Package>> |
| // nestedPackage->collectNested(nestedPackage)->flatten() is Bag<Package> |
| assertQueryEquals(pkg1, expected2, "nestedPackage.nestedPackage"); |
| assertQueryResults(pkg1, "Sequence{1,2}", "let s:Sequence(OclAny) = Sequence{'a','bb'} in s->collect(oclAsType(String)).size()"); |
| } |
| |
| /** |
| * Tests that parsing fails, in the case of an unknown property in a |
| * collection navigation, with an appropriate parse failure, not a |
| * <code>ClassCastException</code>. |
| */ |
| @Test public void test_implicitCollect_unknownAttribute_232669() { |
| assertBadInvariant(SemanticException.class, Diagnostic.ERROR, |
| "nestedPackage.unknownAttribute", |
| OCLMessages.UnresolvedProperty_ERROR_, "unknownAttribute", "Set(Package)"); |
| } |
| |
| /** |
| * Tests that parsing fails, in the case of an unknown operation in a |
| * collection navigation, with an appropriate parse failure, not a |
| * <code>ClassCastException</code>. |
| */ |
| @Test public void test_implicitCollect_unknownOperation_232669() { |
| assertBadInvariant(SemanticException.class, Diagnostic.ERROR, |
| "nestedPackage.unknownOperation(self)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "unknownOperation", "Set(Package)", "self"); |
| } |
| |
| /** |
| * Tests that the collect() iterator correctly flattens its result. |
| */ |
| @Test public void test_collect_flattens_217461() { |
| String self = "foo"; |
| CollectionTypeId typeId = TypeId.SEQUENCE.getSpecializedId(TypeId.STRING); |
| SequenceValue expected = idResolver.createSequenceOfEach(typeId, "THIS AND", "THAT", "THE OTHER"); |
| |
| assertQueryEquals(self, expected, "Sequence{Sequence{'this and', 'that'}, Sequence{'the other'}}->collect(s : Sequence(String) | s.toUpperCase())"); |
| } |
| |
| /** |
| * Tests that the collect() iterator correctly deals with empty collections. |
| */ |
| @Test public void test_collect_empty_217461() { |
| String self = "foo"; |
| List<String> expected = Collections.emptyList(); |
| |
| assertQueryEquals(self, expected, "let c : Sequence(OrderedSet(String)) = Sequence{} in c->collect(s : OrderedSet(String) | s.toUpperCase())"); |
| } |
| |
| /** |
| * Tests the collectNested() iterator. |
| */ |
| @Test public void test_collectNested() { |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.BAG.getSpecializedId(packageType.getTypeId()); |
| CollectionValue expected1 = idResolver.createBagOfEach(typeId, "pkg2", "bob", "pkg3"); |
| |
| // complete form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collectNested(p : ocl::Package | p.name)"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collectNested(p | p.name)"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expected1, "nestedPackage->collectNested(name)"); |
| |
| // nested collections not flattened |
| Set<org.eclipse.ocl.examples.pivot.Package> e1 = Collections.singleton(jim); |
| Set<?> e2 = Collections.EMPTY_SET; |
| HashSet<Object> e3 = new HashSet<Object>(Arrays.asList(new Object[] {pkg4, pkg5})); |
| CollectionValue expected2 = idResolver.createBagOfEach(typeId, e1, e2, e3); |
| |
| assertQueryEquals(pkg1, expected2, "nestedPackage->collectNested(nestedPackage)"); |
| // Bug 423489 - ensure return is collection of body type not source type |
| assertQueryResults(pkg1, "Sequence{1,2}", "let s:Sequence(OclAny) = Sequence{'a','bb'} in s->collectNested(oclAsType(String)).size()"); |
| assertQueryResults(pkg1, "Sequence{Sequence{1,2},Sequence{3,4}}", "let s:Sequence(Sequence(OclAny)) = Sequence{Sequence{'a','bb'},Sequence{'ccc','dddd'}} in s->collectNested(oclAsType(Sequence(String)))->collectNested(s | s.size())"); |
| // Bug 423490 - ensure nested iteration uses iterator as implicit source |
| assertQueryResults(pkg1, "Sequence{2,1}", "let s:Sequence(Sequence(OclAny)) = Sequence{Sequence{'a','bb'},Sequence{'ccc'}} in s->collectNested(size())"); |
| } |
| |
| /** |
| * Tests the sortedBy() iterator. |
| */ |
| @Test public void test_sortedBy() { |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.ORDERED_SET.getSpecializedId(packageType.getTypeId()); |
| OrderedSetValue expectedSet = idResolver.createOrderedSetOfEach(typeId, bob, pkg2, pkg3); |
| |
| // complete form |
| assertQueryEquals(pkg1, expectedSet, "nestedPackage->sortedBy(p : ocl::Package | p.name)"); |
| |
| // shorter form |
| assertQueryEquals(pkg1, expectedSet, "nestedPackage->sortedBy(p | p.name)"); |
| |
| // shortest form |
| assertQueryEquals(pkg1, expectedSet, "nestedPackage->sortedBy(name)"); |
| |
| CollectionTypeId stringsTypeId = TypeId.SEQUENCE.getSpecializedId(TypeId.STRING); |
| SequenceValue expected = idResolver.createSequenceOfEach(stringsTypeId, "a", "b", "c", "d", "e"); |
| assertQueryEquals(pkg1, expected, "Bag{'d', 'b', 'e', 'a', 'c'}->sortedBy(e | e)"); |
| assertQueryResults(null, "Sequence{'x', 'aa', 'zzz', 'zzz', 'zzz', 'yyyy', 'yyyy'}", "Bag{'x', 'yyyy', 'zzz', 'aa', 'zzz', 'yyyy', 'zzz'}->sortedBy(size())"); |
| } |
| |
| /** |
| * Tests the closure() iterator. |
| */ |
| // pkg1 |
| // pkg1::pkg2 |
| // pkg1::pkg2::jim |
| // pkg1::bob |
| // pkg1::pkg3 |
| // pkg1::pkg3::pkg4 |
| // pkg1::pkg3::pkg5 |
| // pkg1::pkg3::pkg5::george |
| @Test public void test_closure() { |
| @SuppressWarnings("null") @NonNull Type packageType = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(packageType.getTypeId()); |
| CollectionValue expected1 = idResolver.createSetOfEach(typeId, pkg1, pkg3, pkg5, george); // closure does include sources (george) |
| assertQueryEquals(george, expected1, "self.oclAsType(Package)->closure(nestingPackage)"); |
| |
| CollectionValue expected2 = idResolver.createSetOfEach(typeId, pkg1, pkg2, jim, bob, pkg3, pkg4, pkg5, george); |
| // CollectionValue expected2a = metaModelManager.createOrderedSetValue(null, pkg2, jim, bob, pkg3, pkg4, pkg5, george); |
| assertQueryEquals(pkg1, expected2, "self.oclAsType(Package)->closure(nestedPackage)"); |
| // FIXME not a valid test for UML's unordered nested packages |
| // assertQueryEquals(pkg1, expected2a, "self->asSequence()->closure(nestedPackage)"); |
| assertQueryEquals(pkg1, expected2, "self.oclAsType(Package)->closure(nestedPackage->asSequence())"); |
| SetValue expected3 = idResolver.createSetOfEach(typeId, pkg1, pkg2, jim, bob, pkg3, pkg4, pkg5, george); |
| assertQueryEquals(pkg1, expected3, "self.oclAsType(Package)->asBag()->closure(nestedPackage)"); |
| assertQueryEquals(pkg1, expected3, "self.oclAsType(Package)->closure(nestedPackage->asBag())"); |
| |
| // empty closure |
| CollectionTypeId collectedId = expected1.getTypeId(); |
| // @SuppressWarnings("unused") DomainType elementType = collectionType.getElementType(); |
| assertQueryEquals(pkg1, idResolver.createSetOfEach(collectedId, pkg1), "self.oclAsType(Package)->closure(nestingPackage)"); |
| //WIP assertQueryNotEquals(pkg1, getEmptySetValue(), "self->closure(nestingPackage)"); |
| // empty closure |
| assertQueryEquals(pkg1, idResolver.createOrderedSetOfEach(collectedId, pkg1), "self.oclAsType(Package)->asSequence()->closure(nestingPackage)"); |
| //WIP assertQueryNotEquals(pkg1, metaModelManager.createOrderedSetValue(metaModelManager.getOrderedSetType(elementType)), "self->asSequence()->closure(nestingPackage)"); |
| } |
| |
| /** |
| * Tests that the closure() iterator handles cycles. |
| */ |
| @Test public void test_closure_cycles() { |
| @SuppressWarnings("null") @NonNull Type packageMetaclass = metaModelManager.getPivotType("Package"); |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(packageMetaclass.getTypeId()); |
| Property nestedPackage = getAttribute(packageMetaclass, "nestedPackage", packageMetaclass); |
| Property nestingPackage = getAttribute(packageMetaclass, "nestingPackage", packageMetaclass); |
| SetValue expected = idResolver.createSetOfEach(typeId, nestedPackage, nestingPackage); // cyclic closure *does* include self |
| assertQueryEquals(nestingPackage, expected, "self->closure(opposite)"); |
| assertQueryEquals(nestedPackage, expected, "self->closure(opposite)"); |
| } |
| |
| /** |
| * Tests parsing the closure of operation calls. |
| */ |
| @Test public void test_closure_operations() { |
| Resource fakeResource = new XMIResourceFactoryImpl().createResource(URI.createURI("fake")); |
| Root fakeRoot = metaModelManager.createRoot(null); |
| org.eclipse.ocl.examples.pivot.Package fakePkg = createPackage(fakeRoot, "fake"); |
| fakeResource.getContents().add(fakePkg); |
| org.eclipse.ocl.examples.pivot.Class fake = createOwnedClass(fakePkg, "Fake", false); |
| createGeneralization(fake, metaModelManager.getOclAnyType()); |
| Operation getFakes = createOwnedOperation(fake, "getFakes", null, null, fake, true); |
| getFakes.setType(metaModelManager.getSetType(fake, null, null)); |
| |
| assertQuery(fake, "self->closure(getFakes())"); |
| } |
| |
| /** |
| * Tests the validation of the closure() iterator. |
| * |
| @Test public void test_closureValidation() { |
| // non-recursive reference |
| assertQueryInvalid(pkg1, "self->closure(xyzzy)"); |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "self->closure(ownedType)", |
| OCLMessages.NonStd_Iterator_, "closure"); |
| } */ |
| |
| /** |
| * Tests the validation of the closure() iterator for conformance of the |
| * body type with the iterator variable (source element) type. |
| */ |
| @Test public void test_closureValidation_typeConformance_154695() { |
| Resource fakeResource = new XMIResourceFactoryImpl().createResource(URI.createURI("fake")); |
| Root fakeRoot = metaModelManager.createRoot(null); |
| org.eclipse.ocl.examples.pivot.Package fakePkg = createPackage(fakeRoot, "fake"); |
| fakeResource.getContents().add(fakePkg); |
| org.eclipse.ocl.examples.pivot.Class fake = createOwnedClass(fakePkg, "Fake", false); |
| @SuppressWarnings("unused") |
| Operation getFakes = createOwnedOperation(fake, "getFakes", null, null, metaModelManager.getSetType(fake, null, null), true); |
| |
| // subclass the Fake class |
| org.eclipse.ocl.examples.pivot.Class subFake = createOwnedClass(fakePkg, "Subfake", false); |
| createGeneralization(subFake, fake); |
| createGeneralization(fake, metaModelManager.getOclAnyType()); |
| |
| // get sub-fakes from a fake |
| @SuppressWarnings("unused") |
| Operation getSubFakes = createOwnedOperation(fake, "getSubFakes", null, null, metaModelManager.getSetType(subFake, null, null), true); |
| |
| helper.setContext(subFake); |
| |
| // this should not parse because the result of the closure |
| // expression |
| // is more general than the iterator variable, so cannot be |
| // assigned recursively |
| assertValidationErrorQuery("self->closure(getFakes())", |
| OCLMessages.IncompatibleBodyType_WARNING_, fake, subFake); |
| |
| // this should parse OK because the result of the closure expression |
| // is more specific than the iterator variable, so it can be |
| // assigned recursively |
| assertQuery(fake, "self->closure(getSubFakes())"); |
| } |
| /** |
| * Tests that the closure() body is not necessarily compatible. |
| */ |
| @Test public void test_closure_body_393509() { |
| @SuppressWarnings("null") @NonNull Type packageMetaclass = metaModelManager.getPivotType("Package"); |
| @SuppressWarnings("null") @NonNull Type propertyMetaclass = metaModelManager.getPivotType("Property"); |
| CollectionTypeId typeId = TypeId.SET.getSpecializedId(packageMetaclass.getTypeId()); |
| Property nestingPackage = getAttribute(packageMetaclass, "nestingPackage", packageMetaclass); |
| SetValue expected = idResolver.createSetOfEach(typeId, nestingPackage, packageMetaclass, packageMetaclass.eContainer(), packageMetaclass.eContainer().eContainer()); |
| assertQueryEquals(nestingPackage, expected, "self->closure(i : OclElement | i.oclContainer())"); |
| assertValidationErrorQuery2(propertyMetaclass, "self->closure(oclContainer())", OCLMessages.IncompatibleBodyType_WARNING_, "OclElement", "Property"); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Test public void test_closure_recursions_401302() throws IOException { |
| if (!EcorePlugin.IS_ECLIPSE_RUNNING) { |
| OCLinEcoreStandaloneSetup.doSetup(); |
| } |
| MetaModelManager metaModelManager = new MetaModelManager(); |
| String nodeModel = |
| "package nodes : nodes = 'http://nodes'{\n" + |
| // " class Root {\n" + |
| // " property nodes : Node[*] {composes};\n" + |
| // " }\n" + |
| " class Node {\n" + |
| " property nodes : Node[*] {ordered,!unique};\n" + |
| " property name : String;\n" + |
| " }\n" + |
| "}\n"; |
| URI uri = createEcoreFile(metaModelManager, "NodeModel", nodeModel); |
| metaModelManager.dispose(); |
| Resource ecoreResource = resourceSet.getResource(uri, true); |
| EPackage nodesEPackage = (EPackage) ecoreResource.getContents().get(0); |
| // EClass rootEClass = (EClass) nodesEPackage.getEClassifier("Root"); |
| EClass nodeEClass = (EClass) nodesEPackage.getEClassifier("Node"); |
| EAttribute nameEAttribute = (EAttribute) nodeEClass.getEStructuralFeature("name"); |
| EReference nodesEReference = (EReference) nodeEClass.getEStructuralFeature("nodes"); |
| EFactory nodesEFactory = nodesEPackage.getEFactoryInstance(); |
| // EObject root = nodesEFactory.create(rootEClass); |
| EObject node1 = nodesEFactory.create(nodeEClass); |
| EObject node2 = nodesEFactory.create(nodeEClass); |
| EObject node3 = nodesEFactory.create(nodeEClass); |
| EObject node4 = nodesEFactory.create(nodeEClass); |
| EObject node5 = nodesEFactory.create(nodeEClass); |
| node1.eSet(nameEAttribute, "node1"); |
| node2.eSet(nameEAttribute, "node2"); |
| node3.eSet(nameEAttribute, "node3"); |
| node4.eSet(nameEAttribute, "node4"); |
| node5.eSet(nameEAttribute, "node5"); |
| // |
| ((List<EObject>)node1.eGet(nodesEReference)).add(node2); |
| // |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node1); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node1); // This repetition terminated recursion erroneously |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node2); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node3); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node4); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node5); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node2); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node1); |
| ((List<EObject>)node2.eGet(nodesEReference)).add(node1); |
| assertQueryEquals(node1, 5, "self->closure(nodes)->size()"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_forAll_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->forAll('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->forAll(2)"); // Bug 415669 |
| |
| assertQueryNull(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->forAll(b and b)"); |
| |
| // check that the "check" API interprets invalid as a constraint |
| // violation |
| assertInvariantFalse(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1}->forAll(b and b)"); |
| |
| // same deal for a null value (in the forAll case) |
| assertQueryNull(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->forAll(null.oclAsType(Boolean))"); |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->forAll(Sequence{}->first())"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_exists_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->exists('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->exists(2)"); // Bug 415669 |
| |
| assertQueryNull(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->exists(b and b)"); |
| |
| // same deal for a null value (in the exists case) |
| assertQueryNull(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->exists(null.oclAsType(Boolean))"); |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->exists(Sequence{}->first())"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_one_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->one('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->one(2)"); // Bug 415669 |
| |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->one(b and b)"); |
| |
| // same deal for a null value (in the one case) |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->one(null.oclAsType(Boolean))"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_any_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->any('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->any(2)"); // Bug 415669 |
| |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->any(b and b)"); |
| |
| // same deal for a null value (in the any case) |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->any(null.oclAsType(Boolean))"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_select_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->select('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->select(2)"); // Bug 415669 |
| |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->select(b and b)"); |
| |
| // same deal for a null value (in the exists case) |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->select(null.oclAsType(Boolean))"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_reject_invalidBody_142518() { |
| assertQueryInvalid(null, "Bag{1, 2, 3}->reject('true')"); // Bug 415669 |
| assertQueryInvalid(null, "Bag{1, 2, 3}->reject(2)"); // Bug 415669 |
| |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->reject(b and b)"); |
| |
| // same deal for a null value (in the exists case) |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->reject(null.oclAsType(Boolean))"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the |
| * isUnique iterator expression treats it like any other value. |
| */ |
| @Test public void test_isUnique_invalidBody_142518() { |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->isUnique(Sequence{}->first())"); |
| |
| assertQueryFalse(EcorePackage.eINSTANCE, |
| "let b:Boolean = null in Bag{1, 2, 3}->isUnique(null)"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_collect_invalidBody_142518() { |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->collect(Sequence{}->first())"); |
| |
| // in the case of a null value, null is allowed in a collection, so |
| // it does not result in invalid |
| CollectionTypeId typeId = TypeId.BAG.getSpecializedId(TypeId.OCL_ANY); |
| BagValue expected = idResolver.createBagOfEach(typeId, getNull(), getNull(), getNull()); |
| assertQueryEquals(EcorePackage.eINSTANCE, expected, |
| "let b:Boolean = null in Bag{1, 2, 3}->collect(null)"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_collectNested_invalidBody_142518() { |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->collectNested(Sequence{}->first())"); |
| |
| // in the case of a null value, null is allowed in a collection, so |
| // it does not result in invalid |
| Set<BigInteger> e1 = Collections.singleton(BigInteger.valueOf(1)); |
| Object e2 = getNull(); |
| Set<BigInteger> e3 = Collections.singleton(BigInteger.valueOf(3)); |
| CollectionTypeId typeId = TypeId.BAG.getSpecializedId(TypeId.INTEGER); |
| BagValue expected = idResolver.createBagOfEach(typeId, e1, e2, e3); |
| assertQueryEquals(EcorePackage.eINSTANCE, expected, |
| "let b:Boolean = null in Bag{1, 2, 3}->collectNested(e | if e = 2 then null else Set{e} endif)"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_closure_invalidBody_142518() { |
| assertQueryInvalid(getUMLMetamodel(), |
| "let c : ocl::Type = invalid in ownedType->closure(c)", EvaluatorMessages.InvalidLiteral, InvalidValueException.class); |
| |
| // in the case of a null value, null is allowed in a collection, so |
| // it does not result in invalid |
| assertQueryResults(null, "Set{5, null}", |
| "let c : Set(UnlimitedNatural) = Set{null} in 5->closure(c)"); |
| |
| // Set<Object> expected = Collections.singleton(getNull()); |
| // assertQueryEquals(EcorePackage.eINSTANCE, expected, |
| // "let c : Set(ocl::Type) = Set{null} in ownedType->closure(c)"); |
| } |
| |
| /** |
| * Tests that when the body of an iterator results in invalid, the entire |
| * iterator expression's value is invalid. |
| */ |
| @Test public void test_sortedBy_invalidBody_142518() { |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "let s : String = null in Bag{1, 2, 3}->sortedBy(s.size())", DomainUtil.bind(EvaluatorMessages.TypedValueRequired, TypeId.STRING_NAME, ValuesUtil.getTypeName(null)), InvalidValueException.class); |
| |
| // same deal for null values |
| assertQueryInvalid(EcorePackage.eINSTANCE, |
| "Bag{1, 2, 3}->sortedBy(null.oclAsType(Integer))", DomainUtil.bind(EvaluatorMessages.UndefinedBody, "sortedBy"), InvalidValueException.class); |
| |
| } |
| |
| /** |
| * Tests that the generic iterate() iterator returns invalid when the |
| * source collection is null or invalid. |
| */ |
| @Test public void test_iterateWithNullSource_143996() { |
| assertQueryInvalid(pkg1, |
| "let e : Collection(ocl::Package) = null in e->iterate(" + |
| "p : ocl::Package; s : String = '' | s.concat(p.name))", DomainUtil.bind(EvaluatorMessages.TypedValueRequired, TypeId.COLLECTION_NAME, ValuesUtil.getTypeName(null)), InvalidValueException.class); |
| |
| assertQueryInvalid(pkg1, |
| "let e : Collection(ocl::Package) = invalid in e->iterate(" + |
| "p : ocl::Package; s : String = '' | s.concat(p.name))", EvaluatorMessages.InvalidLiteral, InvalidValueException.class); |
| } |
| |
| /** |
| * Tests that the exists() iterator return invalid when the source |
| * collection is null or invalid. |
| */ |
| @Test public void test_existsWithNullSource_143996() { |
| assertQueryInvalid(pkg1, |
| "let e : Collection(ocl::Package) = null in e->exists(" + |
| "p : ocl::Package | p.name = 'bob')", DomainUtil.bind(EvaluatorMessages.TypedValueRequired, TypeId.COLLECTION_NAME, ValuesUtil.getTypeName(null)), InvalidValueException.class); |
| |
| assertQueryInvalid(pkg1, |
| "let e : Collection(ocl::Package) = invalid in e->exists(" + |
| "p : ocl::Package | p.name = 'bob')", EvaluatorMessages.InvalidLiteral, InvalidValueException.class); |
| } |
| |
| /** |
| * Tests the exists iterator with multiple iterator variables. |
| */ |
| @Test public void test_exists_multipleIteratorVariables() { |
| assertInvariantTrue(pkg1, "Sequence{1, 2, 3, 4}->exists(e1, e2 | e1 = e2)"); |
| assertInvariantTrue(pkg1, "Sequence{1, 2, 3, 4}->exists(e1, e2 | (e1 + e2) = 7)"); |
| assertInvariantFalse(pkg1, "Sequence{1, 2, 3, 4}->exists(e1, e2 | (e1 + e2) = 0)"); |
| |
| // when there are no values, the the desired result implictly |
| // does not occur |
| assertInvariantFalse(pkg1, "Sequence{}->exists(e1, e2 | e1 = e2)"); |
| } |
| |
| /** |
| * Tests the forAll iterator with multiple iterator variables. |
| */ |
| @Test public void test_forAll_multipleIteratorVariables() { |
| assertInvariantFalse(pkg1, "Sequence{1, 2, 3, 4}->forAll(e1, e2 | e1 = e2)"); |
| |
| assertInvariantTrue(pkg1, "Sequence{1, 2, 3, 4}->forAll(e1, e2 | (e1 + e2) > e1)"); |
| |
| // when there are no values, the the desired result implictly occurs |
| assertInvariantTrue(pkg1, "Sequence{}->forAll(e1, e2 | e1 = e2)"); |
| } |
| |
| /** |
| * Tests the validation the number of iterator variables for iterators that |
| * do not support multiple variables. |
| */ |
| @Test public void test_invalidMultipleIteratorVariables() { |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, // FIXME Bug 296990 |
| "Sequence{'a', 'b', 'c'}->exists(e1, e2, e3 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "exists", "Sequence(String)", "e1, e2, e3| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, // FIXME Bug 296990 |
| "Sequence{'a', 'b', 'c'}->forAll(e1, e2, e3 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "forAll", "Sequence(String)", "e1, e2, e3| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->collect(e1, e2 | Tuple{a : String = e1, b : String = e2})", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "collect", "Sequence(String)", "e1, e2| Tuple{a : String = e1, b : String = e2}"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->any(e1, e2 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "any", "Sequence(String)", "e1, e2| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->one(e1, e2 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "one", "Sequence(String)", "e1, e2| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->select(e1, e2 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "select", "Sequence(String)", "e1, e2| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->reject(e1, e2 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "reject", "Sequence(String)", "e1, e2| e1 = e2"); |
| |
| assertBadQuery(SemanticException.class, Diagnostic.ERROR, |
| "Sequence{'a', 'b', 'c'}->isUnique(e1, e2 | e1 = e2)", |
| OCLMessages.UnresolvedOperationCall_ERROR_, "isUnique", "Sequence(String)", "e1, e2| e1 = e2"); |
| } |
| |
| /** |
| * Test to check the validation of the <tt>sortedBy</tt> iterator, that |
| * the body expression type has a <tt><</tt> operation. |
| */ |
| @Test public void test_sortedByRequiresComparability_192729() { |
| Type context = metaModelManager.getPivotType("Package"); |
| Type type = metaModelManager.getPivotType("Type"); |
| assertValidationErrorQuery("ownedType->sortedBy(e | e)", |
| OCLMessages.UnresolvedOperation_ERROR_, LibraryConstants.COMPARE_TO, type + ""); |
| |
| assertQuery(context, "ownedType->sortedBy(e | e.name)"); |
| loadEPackage("ecore", EcorePackage.eINSTANCE); |
| |
| // EDate defines an OclComparable::compareTo by having a java.lang.Comparable instance class |
| assertQuery(context, "let dates : Sequence(ecore::EDate) = Sequence{} in dates->sortedBy(e | e)"); |
| // EInt defines OclComparable::compareTo by having a behavioral mapping to the Integer type |
| assertQueryResults(context, "Sequence{1,7,9}", "let values : Sequence(ecore::EInt) = Sequence{1,9,7} in values->sortedBy(e | e)"); |
| } |
| } |