Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package '18-Use Case' {
part def Vehicle;
part def Person;
part def Environment;
part def 'Fuel Station';
use case 'provide transportation' {
subject vehicle: Vehicle;
actor driver: Person;
actor passengers: Person[0..4];
actor environment: Environment;
objective {
doc
/*
* Satisfy mission requirements to transport driver and passengers
* from starting location to ending location in conformance with
* the driving profile and meet the mission requirements for safety,
* reliability, comfort, and affordability.
*/

}
:>> start {
doc
/* Mock-up of a pre-condition. */
assert constraint { doc /* Vehicle at starting location */ }
}
first start;
then include 'enter vehicle' {
subject;
actor :>> driver = 'provide transportation'::driver;
actor :>> passengers = 'provide transportation'::passengers;
}
then use case 'drive vehicle' {
include 'add fuel'[0..*] {
doc
/*
* Mock-up of an extension point.
* (But reference to 'add fuel' is in the wrong direction, and it doesn't
* make the extension condition sufficient to trigger the behavior.)
*/

subject;
actor :>> fueler = driver;
:>> start {
doc
/* Fuel level < 10% max fuel */
}
}
}
then include 'exit vehicle' {
subject;
actor :>> driver = 'provide transportation'::driver;
actor :>> passengers = 'provide transportation'::passengers;
}
then done;
:>> done {
doc
/* Mock-up of a post-condition. */
assert constraint { doc /* Vehicle at ending location */ }
}
}
use case 'enter vehicle' {
subject vehicle: Vehicle;
actor driver: Person;
actor passengers: Person[0..4];
}
use case 'exit vehicle' {
subject vehicle: Vehicle;
actor driver: Person;
actor passengers: Person[0..4];
}
use case 'add fuel' {
subject vehicle: Vehicle;
actor fueler: Person;
actor 'fuel station': 'Fuel Station';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
<IsPackable>false</IsPackable>
<PreserveCompilationContext>true</PreserveCompilationContext>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
<!-- The validation corpus runs its cases in parallel and each one allocates a large POCO graph while
deserializing the library XMI it references. Workstation GC gives those threads a single heap to
contend on, which is what caps the speed-up; Server GC gives each core its own heap. Test-host
only - it does not affect the shipped libraries. -->
<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace SysML2.NET.Serializer.TextualNotation.Tests.Writers
using SysML2.NET.Serializer.Xmi;

[TestFixture]
[Parallelizable(ParallelScope.Children)]
public class TextualNotationValidationTestFixture
{
/// <summary>
Expand Down Expand Up @@ -136,6 +137,7 @@ public void OneTimeTearDown()
[TestCase("15-Properties-Values-Expressions", "15_19a-Materials with Properties.sysmlx")]
[TestCase("17-Sequence Modeling", "17a-Sequence-Modeling.sysmlx")]
[TestCase("17-Sequence Modeling", "17b-Sequence-Modeling.sysmlx")]
[TestCase("18-Use Case", "18-Use Case.sysmlx")]
public async Task VerifyValidationTextualNotationXmi(string folderName, string fileName)
{
var loggerFactory = LoggerFactory.Create(builder =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2346,7 +2346,7 @@ private void BuildInheritedEntries(IType type, Dictionary<string, HashSet<IEleme
// the names it owns resolvable.
pending.Enqueue((impliedGeneral, isGlobal));

AddImpliedLookupEntries(impliedGeneral, index, isGlobal);
AddImpliedLookupEntries(type, impliedGeneral, index, isGlobal);
}
}

Expand Down Expand Up @@ -2475,10 +2475,24 @@ private List<IType> QueryImpliedGeneralClosure(IType type, List<IType> declaredS
/// <summary>
/// Indexes, for lookup only, the members an implied general contributes.
/// </summary>
/// <param name="inheritingType">The Type that reaches the general through an implied Specialization.</param>
/// <param name="impliedGeneral">The Type reached through an implied Specialization.</param>
/// <param name="index">The destination index.</param>
/// <param name="isGlobal">Whether the owning scope is reached through the global namespace.</param>
private static void AddImpliedLookupEntries(IType impliedGeneral, Dictionary<string, HashSet<IElement>> index, bool isGlobal)
/// <remarks>
/// The contribution is filtered through <c>Type::removeRedefinedFeatures</c>, because a member the
/// inheriting Type REDEFINES is not one of that Type's Memberships. KerML §8.3.3.1.10 derives
/// <c>inheritedMemberships</c> as <c>removeRedefinedFeatures(inheritableMemberships(…))</c>, whose
/// second condition rejects a Membership one of whose redefined Features is a directly
/// <c>redefinedFeature</c> of an <c>ownedFeature</c> of the Type.
/// <para>Without the filter the redefined library member and the local redefinition both land in the
/// same simple-name bucket, so the name reads as shadowed and a reference that should be bare is
/// emitted fully qualified — <c>first 'provide transportation'::start</c> for <c>first start</c>.</para>
/// <para>The declared-supertype path needs no such filter: it reads <c>inheritedMembership</c>, which
/// has already applied it. Only this path bypasses that derivation, because an implied Specialization
/// is detached and its members have to be gathered directly.</para>
/// </remarks>
private static void AddImpliedLookupEntries(IType inheritingType, IType impliedGeneral, Dictionary<string, HashSet<IElement>> index, bool isGlobal)
{
if (impliedGeneral == null)
{
Expand All @@ -2500,6 +2514,16 @@ private static void AddImpliedLookupEntries(IType impliedGeneral, Dictionary<str
// Same atomicity as above: an unimplemented derivation costs this general's contribution.
}

try
{
contributed = inheritingType.RemoveRedefinedFeatures(contributed);
}
catch (NotSupportedException)
{
// Same atomicity again, and it fails safe: an unfiltered redefined member can only lengthen
// a name, never make one resolve to the wrong element.
}

foreach (var member in contributed.Where(member => PassesVisibilityFilter(member, isGlobal)))
{
AddLookupOnlyEntry(index, member);
Expand Down
Loading