diff --git a/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs b/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs index cb31434..3d7f9f3 100755 --- a/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs @@ -462,6 +462,7 @@ namespace Mocha.Core { public static Guid Minimum { get; } = new Guid("{1ff7be8c-fe48-4154-9028-8ee84b7dc367}"); public static Guid Maximum { get; } = new Guid("{dda6c31d-5bea-41a9-a6bc-0e5c189784da}"); + public static Guid First { get; } = new Guid("{4a196b8f-ca55-4f3a-a443-f960bfdb3bc6}"); } public static class RelationalOperators { diff --git a/mocha-dotnet/src/lib/Mocha.Core/MethodImplementations/SelectFromInstanceSetMethodImplementation.cs b/mocha-dotnet/src/lib/Mocha.Core/MethodImplementations/SelectFromInstanceSetMethodImplementation.cs index ef23045..6472693 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/MethodImplementations/SelectFromInstanceSetMethodImplementation.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/MethodImplementations/SelectFromInstanceSetMethodImplementation.cs @@ -15,9 +15,6 @@ // You should have received a copy of the GNU General Public License // along with Mocha.NET. If not, see . -using System.ComponentModel.Design; -using Mocha.Core.Oop; - namespace Mocha.Core.MethodImplementations; public class SelectFromInstanceSetMethodImplementation : MethodImplementation @@ -27,10 +24,16 @@ public class SelectFromInstanceSetMethodImplementation : MethodImplementation public string Order; public object Data; } + private struct OrderableData + { + public string Order; + public T Data; + } public override Guid MethodClassGuid => KnownInstanceGuids.MethodClasses.SelectFromInstanceSetMethod; protected override InstanceHandle ExecuteInternal(Oms oms, OmsContext context, InstanceHandle method) { + //! FIXME ! Guid methodId = oms.GetGlobalIdentifier(method); InstanceHandle irForClass = oms.GetRelatedInstance(method, oms.GetInstance(KnownRelationshipGuids.Method__for__Class)); @@ -43,32 +46,31 @@ public class SelectFromInstanceSetMethodImplementation : MethodImplementation } InstanceHandle usesInstanceSet = oms.GetRelatedInstance(method, oms.GetInstance(KnownRelationshipGuids.Select_from_Instance_Set_Method__uses__Executable_returning_Instance_Set)); - object? instanceSetValues = context.GetWorkData(usesInstanceSet); + // object? instanceSetValues = context.GetWorkData(usesInstanceSet); + object? instanceSetValues = oms.Evaluate(context, usesInstanceSet, InstanceHandle.Empty); InstanceHandle selectionFunction = oms.GetRelatedInstance(method, oms.GetInstance(KnownRelationshipGuids.Select_from_Instance_Set_Method__uses__Selection_Function)); InstanceHandle setFunction = oms.GetRelatedInstance(method, oms.GetInstance(KnownRelationshipGuids.Select_from_Instance_Set_Method__uses__Set_Function)); InstanceHandle orderAttribute = oms.GetRelatedInstance(method, oms.GetInstance(KnownRelationshipGuids.Select_from_Instance_Set_Method__uses_order__Executable_returning_Attribute)); - List list = new List(); + List> list = new List>(); - if (instanceSetValues is IEnumerable) + if (instanceSetValues is System.Collections.IEnumerable ie) { - - } - else if (instanceSetValues is IEnumerable) - { - IEnumerable vals = (IEnumerable)instanceSetValues; - foreach (InstanceWrapper inst in vals) + // here we use the non-generic IEnumerable so we can handle cases where + // you would pass in an IEnumerable, IEnumerable, + // or IEnumerable. Hell, you could even pass in an IEnumerable + // as long as each element in the IEnumerable was some sort of IInstanceReference! + foreach (object o in ie) { - if (inst != null) + if (o is IInstanceReference ir) { - OrderableData od = new OrderableData(); - od.Data = inst.GetHandle(); + OrderableData od = new OrderableData(); + od.Data = ir.GetHandle(); if (orderAttribute != InstanceHandle.Empty) { - InstanceHandle ihWorkData = oms.Execute(context, orderAttribute, inst.GetHandle()); - string order = context.GetWorkData(ihWorkData); - + InstanceHandle ihWorkData = oms.Execute(context, orderAttribute, ir.GetHandle()); + string order = context.GetWorkData(ihWorkData, String.Empty); od.Order = order; } else @@ -79,23 +81,40 @@ public class SelectFromInstanceSetMethodImplementation : MethodImplementation } else { - + // throw new NotSupportedException(); + // design decision: should we silently exclude non-IInstanceReference items since we could + // theoretically support IEnumerable? or should we force users to do the Right Thing(tm)? } } - - list.Sort((c, d) => c.Order.CompareTo(d.Order)); } + list.Sort((c, d) => c.Order.CompareTo(d.Order)); if (list.Count > 0) { - // FIXME: this assumes a hardcoded singular work set - if (selectionFunction == oms.GetInstance(KnownInstanceGuids.SelectionFunctions.Minimum)) + bool returnsWorkSetIsSingular = oms.GetAttributeValue(returnsWorkSet, oms.GetInstance(KnownAttributeGuids.Boolean.Singular)); + + IEnumerable retval = [ ]; + if (selectionFunction == oms.GetInstance(KnownInstanceGuids.SelectionFunctions.First)) { - context.SetWorkData(returnsWorkSet, list[0].Data); + retval = [ list.First().Data.GetHandle() ]; + } + // FIXME: this assumes a hardcoded singular work set + else if (selectionFunction == oms.GetInstance(KnownInstanceGuids.SelectionFunctions.Minimum)) + { + retval = [ list.First().Data.GetHandle() ]; } else if (selectionFunction == oms.GetInstance(KnownInstanceGuids.SelectionFunctions.Maximum)) { - context.SetWorkData(returnsWorkSet, list[list.Count - 1].Data); + retval = [ list.Last().Data.GetHandle() ]; + } + + if (returnsWorkSetIsSingular) + { + context.SetWorkData(returnsWorkSet, retval.First()); + } + else + { + context.SetWorkData(returnsWorkSet, retval); } } return returnsWorkSet; diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/SelectFromInstanceSetMethodTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/SelectFromInstanceSetMethodTests.cs index d11e0ea..14d8d8b 100644 --- a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/SelectFromInstanceSetMethodTests.cs +++ b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/SelectFromInstanceSetMethodTests.cs @@ -30,7 +30,7 @@ public class SelectFromInstanceSetMethodTests : MethodTestsBase // MethodReturningInstanceSet m_Access_Modifier__get__Most_Restrictive_from_Set = (MethodReturningInstanceSet) Oms.GetMethod(c_AccessModifier, "get", "Most Restrictive from Set"); InstanceHandle a_Order = Oms.GetInstance(KnownAttributeGuids.Text.Order); - + WorkSet ws_Access_Modifier__Nonsingular = Oms.CreateWorkSet("Access Modifier [Nonsingular]", false); WorkSet ws_Access_Modifier__Singular = Oms.CreateWorkSet("Access Modifier [Singular]", true); @@ -38,7 +38,7 @@ public class SelectFromInstanceSetMethodTests : MethodTestsBase GetAttributeMethod get_Order = methodBuilder.CreateGetAttributeMethod(c_AccessModifier, "get", "Order", a_Order); SelectFromInstanceSetMethod m_Access_Modifier__get__Most_Restrictive_from_Set = methodBuilder.CreateSelectFromInstanceSetMethod(c_AccessModifier, "get", "Most Restrictive from Set", AccessModifier.Public, true, ws_Access_Modifier__Singular, ws_Access_Modifier__Nonsingular, null, Oms.GetInstance(KnownInstanceGuids.SelectionFunctions.Minimum), get_Order.GetHandle()); - + if (m_Access_Modifier__get__Most_Restrictive_from_Set != null) { ReturnInstanceSetMethodBinding rsmb = m_Access_Modifier__get__Most_Restrictive_from_Set.CreateMethodBinding(Oms); @@ -59,4 +59,43 @@ public class SelectFromInstanceSetMethodTests : MethodTestsBase Assert.That((InstanceHandle?)value, Is.EqualTo(AccessModifier.Private.GetHandle())); } } + + [Test] + public void Element__get__First_Element_Content() + { + Class c_Element = Oms.GetInstance(KnownInstanceGuids.Classes.Element); + Class c_ElementContent = Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent); + + GetRelationshipMethod m_Element__get__Element_Contents = Oms.MethodBuilder.CreateGetRelationshipMethod(c_Element, "get", "Element Contents", AccessModifier.Public, Oms.GetInstance(KnownRelationshipGuids.Element__has__Element_Content)); + ReturnInstanceSetMethodBinding Element__get__Element_Contents = m_Element__get__Element_Contents.CreateMethodBinding(Oms); + + GetAttributeMethod m_getOrder = Oms.MethodBuilder.CreateGetAttributeMethod(c_ElementContent, "get", "Order", Oms.GetInstance(KnownAttributeGuids.Text.Order)); + ReturnAttributeMethodBinding Element_Content__get__Order = m_getOrder.CreateMethodBinding(Oms); + + WorkSet wsE = Oms.CreateWorkSet("Returned Element Content [Singular]"); + Oms.SetAttributeValue(wsE, Oms.GetInstance(KnownAttributeGuids.Boolean.Singular), true); + + SelectFromInstanceSetMethod m_getFirstElementContent = Oms.MethodBuilder.CreateSelectFromInstanceSetMethod(c_Element, "get", "First Element Content", AccessModifier.Public, false, wsE, Element__get__Element_Contents, null, Oms.GetInstance(KnownInstanceGuids.SelectionFunctions.First), Element_Content__get__Order); + ReturnInstanceSetMethodBinding getFirstElementContent = m_getFirstElementContent.CreateMethodBinding(Oms); + + InstanceHandle element = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.Element)); + + InstanceHandle ec1 = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent)); + InstanceHandle ec2 = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent)); + InstanceHandle ec3 = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent)); + InstanceHandle ec4 = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent)); + InstanceHandle ec5 = Oms.CreateInstanceOf(Oms.GetInstance(KnownInstanceGuids.Classes.ElementContent)); + + Oms.AssignRelationship(element, Oms.GetInstance(KnownRelationshipGuids.Element__has__Element_Content), new InstanceHandle[] + { + ec1, ec2, ec3, ec4, ec5 + }); + + OmsContext context = Oms.CreateContext(); + context.SetWorkData(c_Element, element); + InstanceHandle ws = Oms.Execute(context, getFirstElementContent); + object? obj = context.GetWorkData(ws); + + Assert.That(obj, Is.EqualTo(ec1)); + } } \ No newline at end of file