Skip to content

Commit

Permalink
Merge branch '619-axivion-ci' of github.com:uni-bremen-agst/SEE into …
Browse files Browse the repository at this point in the history
…619-axivion-ci
  • Loading branch information
koschke committed Sep 14, 2023
2 parents 06daa43 + b98355d commit e198be2
Show file tree
Hide file tree
Showing 8 changed files with 1,538 additions and 435 deletions.
81 changes: 35 additions & 46 deletions Assets/SEE/DataModel/DG/Graph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,25 +272,52 @@ public bool ContainsEdge(Edge edge)
}

/// <summary>
/// If the graph has only a single root, nothing happens. Otherwise
/// all current roots become an immediate child of a newly added
/// root node with given <paramref name="name"/> and <paramref name="type"/>.
/// If the graph has no root, false is returned and <paramref name="root"/>
/// will be null.
///
/// If the graph has exactly one root, nothing happens and false is returned.
/// In this case, <paramref name="root"/> refers to the single root.
///
/// Otherwise all current roots become an immediate child of a newly added
/// root node with given <paramref name="name"/> and <paramref name="type"/>
/// and true is returned. The new root will have toggle attribute
/// <see cref="RootToggle"/>. The given <paramref name="name"/> will be used for
/// the source name and ID of the new root node.
///
/// If <paramref name="name"/> is null or empty, a unique ID will be used.
/// If <paramref name="type"/> is null or empty, <see cref="Graph.UnknownType"/> will be used.
/// </summary>
/// <param name="root">the resulting (new or existing) root or null if there is no root</param>
/// <param name="name">ID of new root node</param>
/// <param name="type">type of new root node</param>
public virtual void AddSingleRoot(string name, string type)
/// <returns>true if a new root node was created</returns>
public virtual bool AddSingleRoot(out Node root, string name = null, string type = null)
{
List<Node> roots = GetRoots();
if (roots.Count > 0)
if (roots.Count > 1)
{
Node newRoot = new Node { SourceName = name, ID = name, Type = type };
AddNode(newRoot);
if (string.IsNullOrWhiteSpace(name))
{
name = Guid.NewGuid().ToString();
}
if (string.IsNullOrWhiteSpace(type))
{
type = Graph.UnknownType;
}
root = new() { SourceName = name, ID = name, Type = type, ToggleAttributes = { RootToggle } };
AddNode(root);
foreach (Node oldRoot in roots)
{
newRoot.AddChild(oldRoot);
root.AddChild(oldRoot);
}

NodeHierarchyHasChanged = true;
return true;
}
else
{
root = roots.FirstOrDefault();
return false;
}
}

Expand Down Expand Up @@ -1372,44 +1399,6 @@ public override int GetHashCode()
return HashCode.Combine(Name, Path);
}

/// <summary>
/// If <paramref name="graph"/> has a single root, nothing is done. Otherwise
/// an artificial root is created and added to the <paramref name="graph"/>
/// All true roots of <paramref name="graph"/> will
/// become children of this artificial root.
/// </summary>
/// <param name="graph">graph where a unique root node should be added</param>
/// <returns>the new artificial root or null if <paramref name="graph"/> has
/// already a single root</returns>
public Node AddRootNodeIfNecessary()
{
// Note: Because this method is called only when a hierarchical layout is to
// be applied (and then both leaves and inner nodes were added to nodeMap), we
// could traverse through graph.GetRoots() or nodeMaps.Keys. It would not make
// a difference. If -- for any reason --, we decide not to create a game object
// for some inner nodes, we should rather iterate on nodeMaps.Keys.
ICollection<Node> graphRoots = GetRoots();

if (graphRoots.Count > 1)
{
Node artificialRoot = new Node
{
ID = $"{Name}#ROOT",
SourceName = $"{Name} (Root)",
Type = graphRoots.First().Type,
ToggleAttributes = { RootToggle }
};
AddNode(artificialRoot);
foreach (Node root in graphRoots)
{
artificialRoot.AddChild(root);
}
return artificialRoot;
}

return null;
}

/// <summary>
/// Returns true if <paramref name="graph"/> is not <c>null</c>.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Assets/SEE/Game/City/SEECityEvolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ private void DrawGraphs(List<Graph> graphs)
{
// Node types have been filtered out. Because of that
// there may now be multiple roots again.
relevantGraph.AddSingleRoot(name: "ROOT", type: Graph.UnknownType);
relevantGraph.AddSingleRoot(out Node _, name: "ROOT", type: Graph.UnknownType);
}
graphs[i] = relevantGraph;
LoadDataForGraphListing(graphs[i]);
Expand Down
5 changes: 2 additions & 3 deletions Assets/SEE/Game/GraphRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,10 @@ public void DrawGraph(Graph graph, GameObject parent)

GameObject AddGameRootNodeIfNecessary(Graph graph, Dictionary<Node, GameObject> nodeMap)
{
Node artificialRoot = graph.AddRootNodeIfNecessary();
if (artificialRoot != null)
if (graph.GetRoots().Count > 1 && graph.AddSingleRoot(out Node artificialRoot))
{
nodeMap[artificialRoot] = DrawNode(artificialRoot);
Debug.Log("Artificial unique root was added.\n");
Debug.Log($"Artificial unique root {artificialRoot.ID} was added.\n");
return nodeMap[artificialRoot];
}
else
Expand Down
67 changes: 38 additions & 29 deletions Assets/SEE/Tools/ReflexionAnalysis/ReflexionGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ private static ReflexionGraph Assemble(Graph ArchitectureGraph, Graph Implementa
}

// Add artificial roots if graph has more than one root node, to physically differentiate the two.
ArchitectureRoot = ArchitectureGraph.AddRootNodeIfNecessary() ?? ArchitectureGraph.GetRoots().FirstOrDefault();
ImplementationRoot = ImplementationGraph.AddRootNodeIfNecessary() ?? ImplementationGraph.GetRoots().FirstOrDefault();
ArchitectureGraph.AddSingleRoot(out ArchitectureRoot);
ImplementationGraph.AddSingleRoot(out ImplementationRoot);

// MappingGraph needn't be labeled, as any remaining/new edge (which must be Maps_To)
// automatically belongs to it
Expand Down Expand Up @@ -153,7 +153,7 @@ private static ReflexionGraph Assemble(Graph ArchitectureGraph, Graph Implementa
}

mergedGraph = mergedGraph.MergeWith<ReflexionGraph>(MappingGraph, suffix);
mergedGraph.AddRootNodeIfNecessary();
mergedGraph.AddSingleRoot(out Node _);
return mergedGraph;

#region Local Functions
Expand Down Expand Up @@ -214,11 +214,14 @@ public override void RemoveEdge(Edge edge)
}
switch (edge.GetSubgraph())
{
case Architecture: RemoveFromArchitecture(edge);
case Architecture:
RemoveFromArchitecture(edge);
break;
case Implementation: RemoveFromImplementation(edge);
case Implementation:
RemoveFromImplementation(edge);
break;
case Mapping: RemoveFromMapping(edge);
case Mapping:
RemoveFromMapping(edge);
break;
default: throw new NotSupportedException("Given edge must be in reflexion graph!");
}
Expand Down Expand Up @@ -317,9 +320,11 @@ public override void AddEdge(Edge edge)
}
switch (DetermineSubgraph(edge))
{
case Architecture: AddToArchitecture(edge);
case Architecture:
AddToArchitecture(edge);
break;
case Implementation: AddToImplementation(edge);
case Implementation:
AddToImplementation(edge);
break;
case Mapping: throw new NotSupportedException("Call `AddToMapping` if you wish to create a MapsTo edge.");
default: throw new NotSupportedException("Given edge must either be in architecture or implementation graph!");
Expand Down Expand Up @@ -391,13 +396,18 @@ public override Edge AddEdge(Node from, Node to, string type)
}

/// <summary>
/// Unsupported method. Do not call this on <see cref="ReflexionGraph"/>.
/// Unsupported method. Do not call this on <see cref="ReflexionGraph"/> once it was
/// initialized, i.e., when <see cref="AnalysisInitialized"/> is true.
///
/// If <see cref="AnalysisInitialized"/> is false, this method is equivalent to
/// <see cref="Graph.AddSingleRoot(out Node, string, string)"/>.
/// </summary>
public override void AddSingleRoot(string name, string type)
/// <exception cref="NotSupportedException">thrown in case the </exception>
public override bool AddSingleRoot(out Node root, string name = null, string type = null)
{
if (!AnalysisInitialized)
{
base.AddSingleRoot(name, type);
return base.AddSingleRoot(out root, name, type);
}
else
{
Expand Down Expand Up @@ -428,33 +438,32 @@ private static ReflexionSubgraph DetermineSubgraph(GraphElement element)
switch (element)
{
// Node with a parent:
case Node { Parent: {} } node:
case Node { Parent: { } } node:
subgraph = DetermineSubgraph(node.Parent);
break;
case Edge edge:
{
subgraph = DetermineSubgraph(edge.Source);
ReflexionSubgraph target = DetermineSubgraph(edge.Target);
if (subgraph == Implementation && target == Architecture)
{
// If edge had the MapsTo type, its subgraph would already reflect that.
throw new NotSupportedException("Mapping edge must have type MapsTo!\n"
+ $"(Offending edge: {edge.ToShortString()})");
subgraph = DetermineSubgraph(edge.Source);
ReflexionSubgraph target = DetermineSubgraph(edge.Target);
if (subgraph == Implementation && target == Architecture)
{
// If edge had the MapsTo type, its subgraph would already reflect that.
throw new NotSupportedException("Mapping edge must have type MapsTo!\n"
+ $"(Offending edge: {edge.ToShortString()})");
}
if (subgraph != target)
{
throw new NotSupportedException("Edge must be connected to nodes within the same graph!\n"
+ $"(Offending edge: {edge.ToShortString()})");
}
break;
}
if (subgraph != target)
{
throw new NotSupportedException("Edge must be connected to nodes within the same graph!\n"
+ $"(Offending edge: {edge.ToShortString()})");
}

break;
}
default: subgraph = None;
default:
subgraph = None;
break;
}
}
return subgraph;
}

}
}
Loading

0 comments on commit e198be2

Please sign in to comment.