Repository: dominikbraun/graph
Pull request #9 (2022-06-29 10:36:00)

Rename `properties` to `traits`
The reason for this is that the term "property" is already occupied in graph theory, see https://en.wikipedia.org/wiki/Graph_property.


Patch:
diff --git a/README.md b/README.md
index 9e946af..1d0c862 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ It supports different kinds of graphs such as directed graphs, acyclic graphs, o
 # Features
 
 * Vertices of any data type, such as `int` or `City`.
-* Optionally combinable graph types and properties.
+* Optionally combinable graph types and traits.
 * Validations considering the graph type, such as cycle detection in acyclic graphs.
 * Determination of graph and vertex properties, such as degree or tree-depth.
 * Non-recursive walks, DFS, and BFS.
@@ -209,10 +209,10 @@ identified by hash values of type `string`.
 g := graph.New(cityHash)
 ```
 
-## Properties
+## Traits
 
-The behavior of a graph, for example when adding or retrieving edges, depends on its properties.
-You can set the graph's properties using the functional options provided by this library:
+The behavior of a graph, for example when adding or retrieving edges, depends on its traits. You
+can set the graph's traits using the functional options provided by this library:
 
 ```go
 g := graph.New(graph.IntHash, graph.Directed(), graph.Weighted())
diff --git a/directed.go b/directed.go
index 9be221b..15cbe54 100644
--- a/directed.go
+++ b/directed.go
@@ -6,22 +6,22 @@ import (
 )
 
 type directed[K comparable, T any] struct {
-	hash       Hash[K, T]
-	properties *properties
-	vertices   map[K]T
-	edges      map[K]map[K]Edge[T]
-	outEdges   map[K]map[K]Edge[T]
-	inEdges    map[K]map[K]Edge[T]
+	hash     Hash[K, T]
+	traits   *traits
+	vertices map[K]T
+	edges    map[K]map[K]Edge[T]
+	outEdges map[K]map[K]Edge[T]
+	inEdges  map[K]map[K]Edge[T]
 }
 
-func newDirected[K comparable, T any](hash Hash[K, T], properties *properties) *directed[K, T] {
+func newDirected[K comparable, T any](hash Hash[K, T], traits *traits) *directed[K, T] {
 	return &directed[K, T]{
-		hash:       hash,
-		properties: properties,
-		vertices:   make(map[K]T),
-		edges:      make(map[K]map[K]Edge[T]),
-		outEdges:   make(map[K]map[K]Edge[T]),
-		inEdges:    make(map[K]map[K]Edge[T]),
+		hash:     hash,
+		traits:   traits,
+		vertices: make(map[K]T),
+		edges:    make(map[K]map[K]Edge[T]),
+		outEdges: make(map[K]map[K]Edge[T]),
+		inEdges:  make(map[K]map[K]Edge[T]),
 	}
 }
 
@@ -61,7 +61,7 @@ func (d *directed[K, T]) WeightedEdgeByHashes(sourceHash, targetHash K, weight i
 	}
 
 	// If the graph was declared to be acyclic, permit the creation of a cycle.
-	if d.properties.isAcyclic {
+	if d.traits.isAcyclic {
 		createsCycle, err := d.CreatesCycleByHashes(sourceHash, targetHash)
 		if err != nil {
 			return fmt.Errorf("failed to check for cycles: %w", err)
diff --git a/graph.go b/graph.go
index f14e583..8d4190c 100644
--- a/graph.go
+++ b/graph.go
@@ -145,7 +145,7 @@ type Graph[K comparable, T any] interface {
 
 // Edge represents a graph edge with a source and target vertex as well as a weight, which has the
 // same value for all edges in an unweighted graph. Even though the vertices are referred to as
-// source and target, whether the graph is directed or not is determined by its properties.
+// source and target, whether the graph is directed or not is determined by its traits.
 type Edge[T any] struct {
 	Source T
 	Target T
@@ -194,14 +194,14 @@ type Hash[K comparable, T any] func(T) K
 // This graph will store vertices of type City, identified by hashes of type string. Both type
 // parameters can be inferred from the hashing function.
 //
-// All properties of the graph can be set using the predefined functional options. They can be
-// combined arbitrarily. This example creates a directed acyclic graph:
+// All traits of the graph can be set using the predefined functional options. They can be combined
+// arbitrarily. This example creates a directed acyclic graph:
 //
 //	g := graph.New(graph.IntHash, graph.Directed(), graph.Acyclic())
 //
-// The obtained Graph implementation is depends on these properties.
-func New[K comparable, T any](hash Hash[K, T], options ...func(*properties)) Graph[K, T] {
-	var p properties
+// The obtained Graph implementation is depends on these traits.
+func New[K comparable, T any](hash Hash[K, T], options ...func(*traits)) Graph[K, T] {
+	var p traits
 
 	for _, option := range options {
 		option(&p)
diff --git a/properties.go b/traits.go
similarity index 59%
rename from properties.go
rename to traits.go
index 7b09f18..f7eb8cf 100644
--- a/properties.go
+++ b/traits.go
@@ -1,6 +1,6 @@
 package graph
 
-type properties struct {
+type traits struct {
 	isDirected bool
 	isAcyclic  bool
 	isWeighted bool
@@ -9,38 +9,38 @@ type properties struct {
 
 // Directed creates a directed graph. This has implications on graph traversal and the order of
 // arguments of the Edge and EdgeByHashes functions.
-func Directed() func(*properties) {
-	return func(p *properties) {
-		p.isDirected = true
+func Directed() func(*traits) {
+	return func(t *traits) {
+		t.isDirected = true
 	}
 }
 
 // Acyclic creates an acyclic graph, which won't allow adding directed edges resulting in a cycle.
-func Acyclic() func(*properties) {
-	return func(p *properties) {
-		p.isAcyclic = true
+func Acyclic() func(*traits) {
+	return func(t *traits) {
+		t.isAcyclic = true
 	}
 }
 
 // Weighted creates a weighted graph. To set weights, use the WeightedEdge and WeightedEdgeByHashes
 // functions.
-func Weighted() func(*properties) {
-	return func(p *properties) {
-		p.isWeighted = true
+func Weighted() func(*traits) {
+	return func(t *traits) {
+		t.isWeighted = true
 	}
 }
 
 // Rooted creates a rooted graph. This is particularly common for building tree data structures.
-func Rooted() func(*properties) {
-	return func(p *properties) {
-		p.isRooted = true
+func Rooted() func(*traits) {
+	return func(t *traits) {
+		t.isRooted = true
 	}
 }
 
 // Tree is an alias for Acyclic and Rooted, since most trees in Computer Science are rooted trees.
-func Tree() func(*properties) {
-	return func(p *properties) {
-		Acyclic()(p)
-		Rooted()(p)
+func Tree() func(*traits) {
+	return func(t *traits) {
+		Acyclic()(t)
+		Rooted()(t)
 	}
 }
diff --git a/undirected.go b/undirected.go
index eb0d107..2a84537 100644
--- a/undirected.go
+++ b/undirected.go
@@ -6,22 +6,22 @@ import (
 )
 
 type undirected[K comparable, T any] struct {
-	hash       Hash[K, T]
-	properties *properties
-	vertices   map[K]T
-	edges      map[K]map[K]Edge[T]
-	outEdges   map[K]map[K]Edge[T]
-	inEdges    map[K]map[K]Edge[T]
+	hash     Hash[K, T]
+	traits   *traits
+	vertices map[K]T
+	edges    map[K]map[K]Edge[T]
+	outEdges map[K]map[K]Edge[T]
+	inEdges  map[K]map[K]Edge[T]
 }
 
-func newUndirected[K comparable, T any](hash Hash[K, T], properties *properties) *undirected[K, T] {
+func newUndirected[K comparable, T any](hash Hash[K, T], traits *traits) *undirected[K, T] {
 	return &undirected[K, T]{
-		hash:       hash,
-		properties: properties,
-		vertices:   make(map[K]T),
-		edges:      make(map[K]map[K]Edge[T]),
-		outEdges:   make(map[K]map[K]Edge[T]),
-		inEdges:    make(map[K]map[K]Edge[T]),
+		hash:     hash,
+		traits:   traits,
+		vertices: make(map[K]T),
+		edges:    make(map[K]map[K]Edge[T]),
+		outEdges: make(map[K]map[K]Edge[T]),
+		inEdges:  make(map[K]map[K]Edge[T]),
 	}
 }
 
@@ -61,7 +61,7 @@ func (u *undirected[K, T]) WeightedEdgeByHashes(sourceHash, targetHash K, weight
 	}
 
 	// If the graph was declared to be acyclic, permit the creation of a cycle.
-	if u.properties.isAcyclic {
+	if u.traits.isAcyclic {
 		createsCycle, err := u.CreatesCycleByHashes(sourceHash, targetHash)
 		if err != nil {
 			return fmt.Errorf("failed to check for cycles: %w", err)
@@ -272,7 +272,7 @@ func (u *undirected[K, T]) edgesAreEqual(a, b Edge[T]) bool {
 		return true
 	}
 
-	if !u.properties.isDirected {
+	if !u.traits.isDirected {
 		return aSourceHash == bTargetHash && aTargetHash == bSourceHash
 	}
 


Test patch:
diff --git a/directed_test.go b/directed_test.go
index 440d174..40494c2 100644
--- a/directed_test.go
+++ b/directed_test.go
@@ -20,7 +20,7 @@ func TestDirected_Vertex(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -51,7 +51,7 @@ func TestDirected_WeightedEdgeByHashes(t *testing.T) {
 	tests := map[string]struct {
 		vertices      []int
 		edgeHashes    [][3]int
-		properties    *properties
+		traits        *traits
 		expectedEdges []Edge[int]
 		// Even though some of the WeightedEdgeByHashes calls might work, at least one of them
 		// could fail - for example if the last call would introduce a cycle.
@@ -60,7 +60,7 @@ func TestDirected_WeightedEdgeByHashes(t *testing.T) {
 		"graph with 2 edges": {
 			vertices:   []int{1, 2, 3},
 			edgeHashes: [][3]int{{1, 2, 10}, {1, 3, 20}},
-			properties: &properties{},
+			traits:     &traits{},
 			expectedEdges: []Edge[int]{
 				{Source: 1, Target: 2, Weight: 10},
 				{Source: 1, Target: 3, Weight: 20},
@@ -69,13 +69,13 @@ func TestDirected_WeightedEdgeByHashes(t *testing.T) {
 		"hashes for non-existent vertices": {
 			vertices:          []int{1, 2},
 			edgeHashes:        [][3]int{{1, 3, 20}},
-			properties:        &properties{},
+			traits:            &traits{},
 			shouldFinallyFail: true,
 		},
 		"edge introducing a cycle in an acyclic graph": {
 			vertices:   []int{1, 2, 3},
 			edgeHashes: [][3]int{{1, 2, 0}, {2, 3, 0}, {3, 1, 0}},
-			properties: &properties{
+			traits: &traits{
 				isAcyclic: true,
 			},
 			shouldFinallyFail: true,
@@ -83,7 +83,7 @@ func TestDirected_WeightedEdgeByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, test.properties)
+		graph := newDirected(IntHash, test.traits)
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -147,7 +147,7 @@ func TestDirected_GetEdgeByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
 		}
@@ -222,7 +222,7 @@ func TestDirected_DFSByHash(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -309,7 +309,7 @@ func TestDirected_BFSByHash(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -402,7 +402,7 @@ func TestDirected_CreatesCycleByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -439,7 +439,7 @@ func TestDirected_DegreeByHash(t *testing.T) {
 	}{}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -492,7 +492,7 @@ func TestDirected_StronglyConnectedComponents(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -539,7 +539,7 @@ func TestDirected_edgesAreEqual(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 		actual := graph.edgesAreEqual(test.a, test.b)
 
 		if actual != test.edgesAreEqual {
@@ -562,7 +562,7 @@ func TestDirected_addEdge(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, edge := range test.edges {
 			sourceHash := graph.hash(edge.Source)
@@ -623,7 +623,7 @@ func TestDirected_predecessors(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newDirected(IntHash, &properties{})
+		graph := newDirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
diff --git a/graph_test.go b/graph_test.go
index 77d7be2..b6c9e6b 100644
--- a/graph_test.go
+++ b/graph_test.go
@@ -10,15 +10,15 @@ func TestNew(t *testing.T) {
 	undirectedType := reflect.TypeOf(&undirected[int, int]{})
 
 	tests := map[string]struct {
-		options      []func(*properties)
+		options      []func(*traits)
 		expectedType reflect.Type
 	}{
 		"no options": {
-			options:      []func(*properties){},
+			options:      []func(*traits){},
 			expectedType: undirectedType,
 		},
 		"directed option": {
-			options:      []func(*properties){Directed()},
+			options:      []func(*traits){Directed()},
 			expectedType: directedType,
 		},
 	}
diff --git a/properties_test.go b/properties_test.go
deleted file mode 100644
index 61b1c3b..0000000
--- a/properties_test.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package graph
-
-import "testing"
-
-func TestDirected(t *testing.T) {
-	tests := map[string]struct {
-		expected *properties
-	}{
-		"directed graph": {
-			expected: &properties{
-				isDirected: true,
-			},
-		},
-	}
-
-	for name, test := range tests {
-		p := &properties{}
-
-		Directed()(p)
-
-		if !propertiesAreEqual(test.expected, p) {
-			t.Errorf("%s: property expectation doesn't match: expected %v, got %v", name, test.expected, p)
-		}
-	}
-}
-
-func TestAcyclic(t *testing.T) {
-	tests := map[string]struct {
-		expected *properties
-	}{
-		"acyclic graph": {
-			expected: &properties{
-				isAcyclic: true,
-			},
-		},
-	}
-
-	for name, test := range tests {
-		p := &properties{}
-
-		Acyclic()(p)
-
-		if !propertiesAreEqual(test.expected, p) {
-			t.Errorf("%s: property expectation doesn't match: expected %v, got %v", name, test.expected, p)
-		}
-	}
-}
-
-func TestWeighted(t *testing.T) {
-	tests := map[string]struct {
-		expected *properties
-	}{
-		"weighted graph": {
-			expected: &properties{
-				isWeighted: true,
-			},
-		},
-	}
-
-	for name, test := range tests {
-		p := &properties{}
-
-		Weighted()(p)
-
-		if !propertiesAreEqual(test.expected, p) {
-			t.Errorf("%s: property expectation doesn't match: expected %v, got %v", name, test.expected, p)
-		}
-	}
-}
-
-func TestRooted(t *testing.T) {
-	tests := map[string]struct {
-		expected *properties
-	}{
-		"rooted graph": {
-			expected: &properties{
-				isRooted: true,
-			},
-		},
-	}
-
-	for name, test := range tests {
-		p := &properties{}
-
-		Rooted()(p)
-
-		if !propertiesAreEqual(test.expected, p) {
-			t.Errorf("%s: property expectation doesn't match: expected %v, got %v", name, test.expected, p)
-		}
-	}
-}
-
-func TestTree(t *testing.T) {
-	tests := map[string]struct {
-		expected *properties
-	}{
-		"tree graph": {
-			expected: &properties{
-				isAcyclic: true,
-				isRooted:  true,
-			},
-		},
-	}
-
-	for name, test := range tests {
-		p := &properties{}
-
-		Tree()(p)
-
-		if !propertiesAreEqual(test.expected, p) {
-			t.Errorf("%s: property expectation doesn't match: expected %v, got %v", name, test.expected, p)
-		}
-	}
-}
-
-func propertiesAreEqual(a, b *properties) bool {
-	return a.isAcyclic == b.isAcyclic &&
-		a.isDirected == b.isDirected &&
-		a.isRooted == b.isRooted &&
-		a.isWeighted == b.isWeighted
-}
diff --git a/traits_test.go b/traits_test.go
new file mode 100644
index 0000000..c978fa8
--- /dev/null
+++ b/traits_test.go
@@ -0,0 +1,121 @@
+package graph
+
+import "testing"
+
+func TestDirected(t *testing.T) {
+	tests := map[string]struct {
+		expected *traits
+	}{
+		"directed graph": {
+			expected: &traits{
+				isDirected: true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		p := &traits{}
+
+		Directed()(p)
+
+		if !traitsAreEqual(test.expected, p) {
+			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
+		}
+	}
+}
+
+func TestAcyclic(t *testing.T) {
+	tests := map[string]struct {
+		expected *traits
+	}{
+		"acyclic graph": {
+			expected: &traits{
+				isAcyclic: true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		p := &traits{}
+
+		Acyclic()(p)
+
+		if !traitsAreEqual(test.expected, p) {
+			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
+		}
+	}
+}
+
+func TestWeighted(t *testing.T) {
+	tests := map[string]struct {
+		expected *traits
+	}{
+		"weighted graph": {
+			expected: &traits{
+				isWeighted: true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		p := &traits{}
+
+		Weighted()(p)
+
+		if !traitsAreEqual(test.expected, p) {
+			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
+		}
+	}
+}
+
+func TestRooted(t *testing.T) {
+	tests := map[string]struct {
+		expected *traits
+	}{
+		"rooted graph": {
+			expected: &traits{
+				isRooted: true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		p := &traits{}
+
+		Rooted()(p)
+
+		if !traitsAreEqual(test.expected, p) {
+			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
+		}
+	}
+}
+
+func TestTree(t *testing.T) {
+	tests := map[string]struct {
+		expected *traits
+	}{
+		"tree graph": {
+			expected: &traits{
+				isAcyclic: true,
+				isRooted:  true,
+			},
+		},
+	}
+
+	for name, test := range tests {
+		p := &traits{}
+
+		Tree()(p)
+
+		if !traitsAreEqual(test.expected, p) {
+			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
+		}
+	}
+}
+
+func traitsAreEqual(a, b *traits) bool {
+	return a.isAcyclic == b.isAcyclic &&
+		a.isDirected == b.isDirected &&
+		a.isRooted == b.isRooted &&
+		a.isWeighted == b.isWeighted
+}
diff --git a/undirected_test.go b/undirected_test.go
index c716bee..11c038b 100644
--- a/undirected_test.go
+++ b/undirected_test.go
@@ -20,7 +20,7 @@ func TestUndirected_Vertex(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -51,7 +51,7 @@ func TestUndirected_WeightedEdgeByHashes(t *testing.T) {
 	tests := map[string]struct {
 		vertices      []int
 		edgeHashes    [][3]int
-		properties    *properties
+		traits        *traits
 		expectedEdges []Edge[int]
 		// Even though some of the WeightedEdgeByHashes calls might work, at least one of them
 		// could fail - for example if the last call would introduce a cycle.
@@ -60,7 +60,7 @@ func TestUndirected_WeightedEdgeByHashes(t *testing.T) {
 		"graph with 2 edges": {
 			vertices:   []int{1, 2, 3},
 			edgeHashes: [][3]int{{1, 2, 10}, {1, 3, 20}},
-			properties: &properties{},
+			traits:     &traits{},
 			expectedEdges: []Edge[int]{
 				{Source: 1, Target: 2, Weight: 10},
 				{Source: 1, Target: 3, Weight: 20},
@@ -69,13 +69,13 @@ func TestUndirected_WeightedEdgeByHashes(t *testing.T) {
 		"hashes for non-existent vertices": {
 			vertices:          []int{1, 2},
 			edgeHashes:        [][3]int{{1, 3, 20}},
-			properties:        &properties{},
+			traits:            &traits{},
 			shouldFinallyFail: true,
 		},
 		"edge introducing a cycle in an acyclic graph": {
 			vertices:   []int{1, 2, 3},
 			edgeHashes: [][3]int{{1, 2, 0}, {2, 3, 0}, {3, 1, 0}},
-			properties: &properties{
+			traits: &traits{
 				isAcyclic: true,
 			},
 			shouldFinallyFail: true,
@@ -83,7 +83,7 @@ func TestUndirected_WeightedEdgeByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, test.properties)
+		graph := newUndirected(IntHash, test.traits)
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -147,7 +147,7 @@ func TestUndirected_GetEdgeByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -267,7 +267,7 @@ func TestUndirected_DFSByHash(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -362,7 +362,7 @@ func TestUndirected_BFSByHash(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -453,7 +453,7 @@ func TestUndirected_CreatesCycleByHashes(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -490,7 +490,7 @@ func TestUndirected_DegreeByHash(t *testing.T) {
 	}{}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)
@@ -526,7 +526,7 @@ func TestUndirected_StronglyConnectedComponents(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		sccs, err := graph.StronglyConnectedComponents()
 
@@ -563,7 +563,7 @@ func TestUndirected_edgesAreEqual(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 		actual := graph.edgesAreEqual(test.a, test.b)
 
 		if actual != test.edgesAreEqual {
@@ -586,7 +586,7 @@ func TestUndirected_addEdge(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, edge := range test.edges {
 			sourceHash := graph.hash(edge.Source)
@@ -679,7 +679,7 @@ func TestUndirected_adjacencies(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := newUndirected(IntHash, &properties{})
+		graph := newUndirected(IntHash, &traits{})
 
 		for _, vertex := range test.vertices {
 			graph.Vertex(vertex)