From c23eaad971cd50468b946f49e1e76dc8357ce2a3 Mon Sep 17 00:00:00 2001
From: zachmann <gabriel.zachmann@kit.edu>
Date: Fri, 13 Nov 2020 10:35:35 +0100
Subject: [PATCH] restructure tests

---
 .../restrictionIsTighterThan_test.go          | 325 -------------
 .../restrictions/restriction_test.go          | 428 +++++++++++++++++-
 .../restrictionsGetExpires_test.go            |  61 ---
 .../restrictionsGetNotBefore_test.go          |  61 ---
 .../issuerUtilsCombineSubIss_test.go          |  25 -
 .../issuerUtilsCompareIssuerURL_test.go       |  42 --
 ...rUtilsGetIssuerWithAndWithoutSlash_test.go |  39 --
 .../utils/issuerUtils/issuerUtils_test.go     |  97 ++++
 internal/utils/utilsCombineURLPath_test.go    |  57 ---
 internal/utils/utilsIntersectSlices_test.go   |  58 ---
 internal/utils/utilsIsSubSet_test.go          |  38 --
 internal/utils/utilsSliceUnion_test.go        |  55 ---
 internal/utils/utilsStringInSlice_test.go     |  52 ---
 internal/utils/utilsUniqueSlice_test.go       |  41 --
 internal/utils/utils_test.go                  | 272 +++++++++++
 15 files changed, 786 insertions(+), 865 deletions(-)
 delete mode 100644 internal/supertoken/restrictions/restrictionIsTighterThan_test.go
 delete mode 100644 internal/supertoken/restrictions/restrictionsGetExpires_test.go
 delete mode 100644 internal/supertoken/restrictions/restrictionsGetNotBefore_test.go
 delete mode 100644 internal/utils/issuerUtils/issuerUtilsCombineSubIss_test.go
 delete mode 100644 internal/utils/issuerUtils/issuerUtilsCompareIssuerURL_test.go
 delete mode 100644 internal/utils/issuerUtils/issuerUtilsGetIssuerWithAndWithoutSlash_test.go
 create mode 100644 internal/utils/issuerUtils/issuerUtils_test.go
 delete mode 100644 internal/utils/utilsCombineURLPath_test.go
 delete mode 100644 internal/utils/utilsIntersectSlices_test.go
 delete mode 100644 internal/utils/utilsIsSubSet_test.go
 delete mode 100644 internal/utils/utilsSliceUnion_test.go
 delete mode 100644 internal/utils/utilsStringInSlice_test.go
 delete mode 100644 internal/utils/utilsUniqueSlice_test.go
 create mode 100644 internal/utils/utils_test.go

diff --git a/internal/supertoken/restrictions/restrictionIsTighterThan_test.go b/internal/supertoken/restrictions/restrictionIsTighterThan_test.go
deleted file mode 100644
index c79e2355..00000000
--- a/internal/supertoken/restrictions/restrictionIsTighterThan_test.go
+++ /dev/null
@@ -1,325 +0,0 @@
-package restrictions
-
-import (
-	"testing"
-
-	"github.com/zachmann/mytoken/internal/model"
-)
-
-func testIsTighter(t *testing.T, a, b Restriction, expected bool) {
-	tighter := a.IsTighterThan(b)
-	if tighter != expected {
-		if expected {
-			t.Errorf("Actually '%+v' is tighter than '%+v'", a, b)
-		} else {
-			t.Errorf("Actually '%+v' is not tighter than '%+v'", a, b)
-		}
-	}
-}
-
-func TestIsTighterThanBothEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{}
-	testIsTighter(t, a, b, true)
-}
-func TestIsTighterThanOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{Scope: "some"}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanNotBefore(t *testing.T) {
-	a := Restriction{NotBefore: 50}
-	b := Restriction{NotBefore: 100}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanNotBeforeOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{NotBefore: 100}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanExpiresAt(t *testing.T) {
-	a := Restriction{ExpiresAt: 200}
-	b := Restriction{ExpiresAt: 100}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanExpiresAtOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{ExpiresAt: 100}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanScope(t *testing.T) {
-	a := Restriction{Scope: "some scopes"}
-	b := Restriction{Scope: "some"}
-	c := Restriction{Scope: "some other"}
-	d := Restriction{Scope: "completely different"}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-	testIsTighter(t, a, c, false)
-	testIsTighter(t, b, c, true)
-	testIsTighter(t, c, a, false)
-	testIsTighter(t, c, b, false)
-	testIsTighter(t, a, d, false)
-	testIsTighter(t, d, a, false)
-}
-func TestIsTighterThanScopeOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{Scope: "some scopes"}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanIP(t *testing.T) {
-	a := Restriction{IPs: []string{"192.168.0.12"}}
-	b := Restriction{IPs: []string{"192.168.0.12", "192.168.0.14"}}
-	c := Restriction{IPs: []string{"192.168.0.0/24"}}
-	d := Restriction{IPs: []string{"192.168.1.2", "192.168.0.12"}}
-	e := Restriction{IPs: []string{"192.168.0.0/24", "192.168.1.2"}}
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, false)
-	testIsTighter(t, a, c, true)
-	testIsTighter(t, b, c, true)
-	testIsTighter(t, c, a, false)
-	testIsTighter(t, c, b, false)
-	testIsTighter(t, a, d, true)
-	testIsTighter(t, d, a, false)
-	testIsTighter(t, a, e, true)
-	testIsTighter(t, e, a, false)
-	testIsTighter(t, d, e, true)
-	testIsTighter(t, e, d, false)
-}
-func TestIsTighterThanIPOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{IPs: []string{"192.168.0.12", "192.168.0.14"}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanGeoIPWhite(t *testing.T) {
-	a := Restriction{GeoIPWhite: []string{"Germany", "USA"}}
-	b := Restriction{GeoIPWhite: []string{"Germany"}}
-	c := Restriction{GeoIPWhite: []string{"France", "Germany"}}
-	d := Restriction{GeoIPWhite: []string{"Japan", "China"}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-	testIsTighter(t, a, c, false)
-	testIsTighter(t, b, c, true)
-	testIsTighter(t, c, a, false)
-	testIsTighter(t, c, b, false)
-	testIsTighter(t, a, d, false)
-	testIsTighter(t, d, a, false)
-}
-func TestIsTighterThanGeoIPWhiteOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{GeoIPWhite: []string{"Germany", "USA"}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanGeoIPBlack(t *testing.T) {
-	a := Restriction{GeoIPBlack: []string{"Germany", "USA"}}
-	b := Restriction{GeoIPBlack: []string{"Germany"}}
-	c := Restriction{GeoIPBlack: []string{"France", "Germany"}}
-	d := Restriction{GeoIPBlack: []string{"Japan", "China"}}
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, false)
-	testIsTighter(t, a, c, false)
-	testIsTighter(t, b, c, false)
-	testIsTighter(t, c, a, false)
-	testIsTighter(t, c, b, true)
-	testIsTighter(t, a, d, false)
-	testIsTighter(t, d, a, false)
-}
-func TestIsTighterThanGeoIPBlackOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{GeoIPBlack: []string{"Germany", "USA"}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanUsagesAT(t *testing.T) {
-	a := Restriction{UsagesAT: model.JSONNullInt{Value: 20, Valid: true}}
-	b := Restriction{UsagesAT: model.JSONNullInt{Value: 10, Valid: true}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanUsagesATOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{UsagesAT: model.JSONNullInt{Value: 10, Valid: true}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanUsagesOther(t *testing.T) {
-	a := Restriction{UsagesOther: model.JSONNullInt{Value: 20, Valid: true}}
-	b := Restriction{UsagesOther: model.JSONNullInt{Value: 10, Valid: true}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-func TestIsTighterThanUsagesOtherOneEmpty(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{UsagesOther: model.JSONNullInt{Value: 20, Valid: true}}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-
-func TestIsTighterThanMultiple1(t *testing.T) {
-	a := Restriction{}
-	b := Restriction{
-		Scope:       "a",
-		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
-	}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-
-func TestIsTighterThanMultiple2(t *testing.T) {
-	a := Restriction{
-		Scope:       "a",
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := Restriction{
-		Scope:       "a b",
-		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
-	}
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, false)
-}
-
-func TestIsTighterThanMultiple3(t *testing.T) {
-	a := Restriction{
-		UsagesAT:    model.JSONNullInt{Value: 100, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 50, Valid: true},
-	}
-	b := Restriction{
-		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
-	}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, false)
-}
-
-func TestIsTighterThanMultiple4(t *testing.T) {
-	a := Restriction{
-		Scope:       "a b c",
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := Restriction{
-		Scope:       "a c b d",
-		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
-	}
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, false)
-}
-func TestIsTighterThanMultipleE(t *testing.T) {
-	a := Restriction{
-		Scope:       "a b c",
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := a
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, true)
-}
-
-func TestIsTighterThanAll1(t *testing.T) {
-	a := Restriction{
-		NotBefore:   500,
-		ExpiresAt:   1000,
-		Scope:       "a b c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := a
-	testIsTighter(t, a, b, true)
-	testIsTighter(t, b, a, true)
-}
-
-func TestIsTighterThanAll2(t *testing.T) {
-	a := Restriction{
-		NotBefore:   500,
-		ExpiresAt:   1000,
-		Scope:       "a b c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := Restriction{
-		NotBefore:   700,
-		ExpiresAt:   1000,
-		Scope:       "a b c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, true)
-}
-
-func TestIsTighterThanAll3(t *testing.T) {
-	a := Restriction{
-		NotBefore:   500,
-		ExpiresAt:   1000,
-		Scope:       "a c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := Restriction{
-		NotBefore:   700,
-		ExpiresAt:   1000,
-		Scope:       "a b c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, false)
-}
-
-func TestIsTighterThanAll4(t *testing.T) {
-	a := Restriction{
-		NotBefore:   500,
-		ExpiresAt:   1000,
-		Scope:       "a b c",
-		Audiences:   []string{"a", "b", "c"},
-		IPs:         []string{"a", "b", "c"},
-		GeoIPWhite:  []string{"a", "b", "c"},
-		GeoIPBlack:  []string{"a", "b", "c"},
-		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
-	}
-	b := Restriction{
-		NotBefore:   700,
-		ExpiresAt:   900,
-		Scope:       "b c",
-		Audiences:   []string{"a", "c"},
-		IPs:         []string{"b", "c"},
-		GeoIPWhite:  []string{"a"},
-		GeoIPBlack:  []string{"a", "b"},
-		UsagesAT:    model.JSONNullInt{Value: 10, Valid: true},
-		UsagesOther: model.JSONNullInt{Value: 0, Valid: true},
-	}
-	testIsTighter(t, a, b, false)
-	testIsTighter(t, b, a, false)
-}
diff --git a/internal/supertoken/restrictions/restriction_test.go b/internal/supertoken/restrictions/restriction_test.go
index 8dce3d98..2aed077a 100644
--- a/internal/supertoken/restrictions/restriction_test.go
+++ b/internal/supertoken/restrictions/restriction_test.go
@@ -6,10 +6,6 @@ import (
 	"github.com/zachmann/mytoken/internal/model"
 )
 
-// import "testing"
-
-//TODO TestTighten
-
 func checkRestrictions(t *testing.T, exp, a Restrictions) {
 	if len(a) != len(exp) {
 		t.Errorf("Expected '%+v', but got '%+v'", exp, a)
@@ -23,7 +19,6 @@ func checkRestrictions(t *testing.T, exp, a Restrictions) {
 		}
 	}
 }
-
 func TestTighten_RestrictEmpty(t *testing.T) {
 	base := Restrictions{}
 	wanted := Restrictions{
@@ -36,7 +31,6 @@ func TestTighten_RestrictEmpty(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RequestEmpty(t *testing.T) {
 	base := Restrictions{
 		{
@@ -57,7 +51,6 @@ func TestTighten_RequestEmpty(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RestrictToOne(t *testing.T) {
 	base := Restrictions{
 		{
@@ -83,7 +76,6 @@ func TestTighten_RestrictToOne(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RestrictToTwo(t *testing.T) {
 	base := Restrictions{
 		{
@@ -113,7 +105,6 @@ func TestTighten_RestrictToTwo(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RestrictConflict(t *testing.T) {
 	base := Restrictions{
 		{
@@ -139,7 +130,6 @@ func TestTighten_RestrictConflict(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RestrictDontCombineTwo(t *testing.T) {
 	base := Restrictions{
 		{
@@ -161,7 +151,6 @@ func TestTighten_RestrictDontCombineTwo(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
-
 func TestTighten_RestrictDontExtendUsages(t *testing.T) {
 	base := Restrictions{
 		{
@@ -189,3 +178,420 @@ func TestTighten_RestrictDontExtendUsages(t *testing.T) {
 	res := Tighten(base, wanted)
 	checkRestrictions(t, expected, res)
 }
+
+func testIsTighter(t *testing.T, a, b Restriction, expected bool) {
+	tighter := a.IsTighterThan(b)
+	if tighter != expected {
+		if expected {
+			t.Errorf("Actually '%+v' is tighter than '%+v'", a, b)
+		} else {
+			t.Errorf("Actually '%+v' is not tighter than '%+v'", a, b)
+		}
+	}
+}
+func TestIsTighterThanBothEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{}
+	testIsTighter(t, a, b, true)
+}
+func TestIsTighterThanOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{Scope: "some"}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanNotBefore(t *testing.T) {
+	a := Restriction{NotBefore: 50}
+	b := Restriction{NotBefore: 100}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanNotBeforeOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{NotBefore: 100}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanExpiresAt(t *testing.T) {
+	a := Restriction{ExpiresAt: 200}
+	b := Restriction{ExpiresAt: 100}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanExpiresAtOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{ExpiresAt: 100}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanScope(t *testing.T) {
+	a := Restriction{Scope: "some scopes"}
+	b := Restriction{Scope: "some"}
+	c := Restriction{Scope: "some other"}
+	d := Restriction{Scope: "completely different"}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+	testIsTighter(t, a, c, false)
+	testIsTighter(t, b, c, true)
+	testIsTighter(t, c, a, false)
+	testIsTighter(t, c, b, false)
+	testIsTighter(t, a, d, false)
+	testIsTighter(t, d, a, false)
+}
+func TestIsTighterThanScopeOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{Scope: "some scopes"}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanIP(t *testing.T) {
+	a := Restriction{IPs: []string{"192.168.0.12"}}
+	b := Restriction{IPs: []string{"192.168.0.12", "192.168.0.14"}}
+	c := Restriction{IPs: []string{"192.168.0.0/24"}}
+	d := Restriction{IPs: []string{"192.168.1.2", "192.168.0.12"}}
+	e := Restriction{IPs: []string{"192.168.0.0/24", "192.168.1.2"}}
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, false)
+	testIsTighter(t, a, c, true)
+	testIsTighter(t, b, c, true)
+	testIsTighter(t, c, a, false)
+	testIsTighter(t, c, b, false)
+	testIsTighter(t, a, d, true)
+	testIsTighter(t, d, a, false)
+	testIsTighter(t, a, e, true)
+	testIsTighter(t, e, a, false)
+	testIsTighter(t, d, e, true)
+	testIsTighter(t, e, d, false)
+}
+func TestIsTighterThanIPOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{IPs: []string{"192.168.0.12", "192.168.0.14"}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanGeoIPWhite(t *testing.T) {
+	a := Restriction{GeoIPWhite: []string{"Germany", "USA"}}
+	b := Restriction{GeoIPWhite: []string{"Germany"}}
+	c := Restriction{GeoIPWhite: []string{"France", "Germany"}}
+	d := Restriction{GeoIPWhite: []string{"Japan", "China"}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+	testIsTighter(t, a, c, false)
+	testIsTighter(t, b, c, true)
+	testIsTighter(t, c, a, false)
+	testIsTighter(t, c, b, false)
+	testIsTighter(t, a, d, false)
+	testIsTighter(t, d, a, false)
+}
+func TestIsTighterThanGeoIPWhiteOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{GeoIPWhite: []string{"Germany", "USA"}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanGeoIPBlack(t *testing.T) {
+	a := Restriction{GeoIPBlack: []string{"Germany", "USA"}}
+	b := Restriction{GeoIPBlack: []string{"Germany"}}
+	c := Restriction{GeoIPBlack: []string{"France", "Germany"}}
+	d := Restriction{GeoIPBlack: []string{"Japan", "China"}}
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, false)
+	testIsTighter(t, a, c, false)
+	testIsTighter(t, b, c, false)
+	testIsTighter(t, c, a, false)
+	testIsTighter(t, c, b, true)
+	testIsTighter(t, a, d, false)
+	testIsTighter(t, d, a, false)
+}
+func TestIsTighterThanGeoIPBlackOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{GeoIPBlack: []string{"Germany", "USA"}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanUsagesAT(t *testing.T) {
+	a := Restriction{UsagesAT: model.JSONNullInt{Value: 20, Valid: true}}
+	b := Restriction{UsagesAT: model.JSONNullInt{Value: 10, Valid: true}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanUsagesATOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{UsagesAT: model.JSONNullInt{Value: 10, Valid: true}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanUsagesOther(t *testing.T) {
+	a := Restriction{UsagesOther: model.JSONNullInt{Value: 20, Valid: true}}
+	b := Restriction{UsagesOther: model.JSONNullInt{Value: 10, Valid: true}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanUsagesOtherOneEmpty(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{UsagesOther: model.JSONNullInt{Value: 20, Valid: true}}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanMultiple1(t *testing.T) {
+	a := Restriction{}
+	b := Restriction{
+		Scope:       "a",
+		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
+	}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanMultiple2(t *testing.T) {
+	a := Restriction{
+		Scope:       "a",
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := Restriction{
+		Scope:       "a b",
+		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
+	}
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, false)
+}
+func TestIsTighterThanMultiple3(t *testing.T) {
+	a := Restriction{
+		UsagesAT:    model.JSONNullInt{Value: 100, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 50, Valid: true},
+	}
+	b := Restriction{
+		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
+	}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, false)
+}
+func TestIsTighterThanMultiple4(t *testing.T) {
+	a := Restriction{
+		Scope:       "a b c",
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := Restriction{
+		Scope:       "a c b d",
+		UsagesAT:    model.JSONNullInt{Value: 50, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 100, Valid: true},
+	}
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, false)
+}
+func TestIsTighterThanMultipleE(t *testing.T) {
+	a := Restriction{
+		Scope:       "a b c",
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := a
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanAll1(t *testing.T) {
+	a := Restriction{
+		NotBefore:   500,
+		ExpiresAt:   1000,
+		Scope:       "a b c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := a
+	testIsTighter(t, a, b, true)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanAll2(t *testing.T) {
+	a := Restriction{
+		NotBefore:   500,
+		ExpiresAt:   1000,
+		Scope:       "a b c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := Restriction{
+		NotBefore:   700,
+		ExpiresAt:   1000,
+		Scope:       "a b c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, true)
+}
+func TestIsTighterThanAll3(t *testing.T) {
+	a := Restriction{
+		NotBefore:   500,
+		ExpiresAt:   1000,
+		Scope:       "a c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := Restriction{
+		NotBefore:   700,
+		ExpiresAt:   1000,
+		Scope:       "a b c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, false)
+}
+func TestIsTighterThanAll4(t *testing.T) {
+	a := Restriction{
+		NotBefore:   500,
+		ExpiresAt:   1000,
+		Scope:       "a b c",
+		Audiences:   []string{"a", "b", "c"},
+		IPs:         []string{"a", "b", "c"},
+		GeoIPWhite:  []string{"a", "b", "c"},
+		GeoIPBlack:  []string{"a", "b", "c"},
+		UsagesAT:    model.JSONNullInt{Value: 20, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 20, Valid: true},
+	}
+	b := Restriction{
+		NotBefore:   700,
+		ExpiresAt:   900,
+		Scope:       "b c",
+		Audiences:   []string{"a", "c"},
+		IPs:         []string{"b", "c"},
+		GeoIPWhite:  []string{"a"},
+		GeoIPBlack:  []string{"a", "b"},
+		UsagesAT:    model.JSONNullInt{Value: 10, Valid: true},
+		UsagesOther: model.JSONNullInt{Value: 0, Valid: true},
+	}
+	testIsTighter(t, a, b, false)
+	testIsTighter(t, b, a, false)
+}
+
+func TestRestrictions_GetExpiresEmpty(t *testing.T) {
+	r := Restrictions{}
+	expires := r.GetExpires()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetExpiresInfinite(t *testing.T) {
+	r := Restrictions{
+		{ExpiresAt: 0},
+	}
+	expires := r.GetExpires()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetExpiresOne(t *testing.T) {
+	r := Restrictions{
+		{ExpiresAt: 100},
+	}
+	expires := r.GetExpires()
+	var expected int64 = 100
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetExpiresMultiple(t *testing.T) {
+	r := Restrictions{
+		{ExpiresAt: 100},
+		{ExpiresAt: 300},
+		{ExpiresAt: 200},
+	}
+	expires := r.GetExpires()
+	var expected int64 = 300
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetExpiresMultipleAndInfinite(t *testing.T) {
+	r := Restrictions{
+		{ExpiresAt: 100},
+		{ExpiresAt: 0},
+		{ExpiresAt: 300},
+		{ExpiresAt: 200},
+	}
+	expires := r.GetExpires()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+
+func TestRestrictions_GetNotBeforeEmpty(t *testing.T) {
+	r := Restrictions{}
+	expires := r.GetNotBefore()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetNotBeforeInfinite(t *testing.T) {
+	r := Restrictions{
+		{NotBefore: 0},
+	}
+	expires := r.GetNotBefore()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetNotBeforeOne(t *testing.T) {
+	r := Restrictions{
+		{NotBefore: 100},
+	}
+	expires := r.GetNotBefore()
+	var expected int64 = 100
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetNotBeforeMultiple(t *testing.T) {
+	r := Restrictions{
+		{NotBefore: 100},
+		{NotBefore: 300},
+		{NotBefore: 200},
+	}
+	expires := r.GetNotBefore()
+	var expected int64 = 100
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
+func TestRestrictions_GetNotBeforeMultipleAndInfinite(t *testing.T) {
+	r := Restrictions{
+		{NotBefore: 100},
+		{NotBefore: 0},
+		{NotBefore: 300},
+		{NotBefore: 200},
+	}
+	expires := r.GetNotBefore()
+	var expected int64 = 0
+	if expected != expires {
+		t.Errorf("Expected %d, but got %d", expected, expires)
+	}
+}
diff --git a/internal/supertoken/restrictions/restrictionsGetExpires_test.go b/internal/supertoken/restrictions/restrictionsGetExpires_test.go
deleted file mode 100644
index fe2a3174..00000000
--- a/internal/supertoken/restrictions/restrictionsGetExpires_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package restrictions
-
-import "testing"
-
-func TestRestrictions_GetExpiresEmpty(t *testing.T) {
-	r := Restrictions{}
-	expires := r.GetExpires()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetExpiresInfinite(t *testing.T) {
-	r := Restrictions{
-		{ExpiresAt: 0},
-	}
-	expires := r.GetExpires()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetExpiresOne(t *testing.T) {
-	r := Restrictions{
-		{ExpiresAt: 100},
-	}
-	expires := r.GetExpires()
-	var expected int64 = 100
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetExpiresMultiple(t *testing.T) {
-	r := Restrictions{
-		{ExpiresAt: 100},
-		{ExpiresAt: 300},
-		{ExpiresAt: 200},
-	}
-	expires := r.GetExpires()
-	var expected int64 = 300
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetExpiresMultipleAndInfinite(t *testing.T) {
-	r := Restrictions{
-		{ExpiresAt: 100},
-		{ExpiresAt: 0},
-		{ExpiresAt: 300},
-		{ExpiresAt: 200},
-	}
-	expires := r.GetExpires()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
diff --git a/internal/supertoken/restrictions/restrictionsGetNotBefore_test.go b/internal/supertoken/restrictions/restrictionsGetNotBefore_test.go
deleted file mode 100644
index c770864e..00000000
--- a/internal/supertoken/restrictions/restrictionsGetNotBefore_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package restrictions
-
-import "testing"
-
-func TestRestrictions_GetNotBeforeEmpty(t *testing.T) {
-	r := Restrictions{}
-	expires := r.GetNotBefore()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetNotBeforeInfinite(t *testing.T) {
-	r := Restrictions{
-		{NotBefore: 0},
-	}
-	expires := r.GetNotBefore()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetNotBeforeOne(t *testing.T) {
-	r := Restrictions{
-		{NotBefore: 100},
-	}
-	expires := r.GetNotBefore()
-	var expected int64 = 100
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetNotBeforeMultiple(t *testing.T) {
-	r := Restrictions{
-		{NotBefore: 100},
-		{NotBefore: 300},
-		{NotBefore: 200},
-	}
-	expires := r.GetNotBefore()
-	var expected int64 = 100
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
-
-func TestRestrictions_GetNotBeforeMultipleAndInfinite(t *testing.T) {
-	r := Restrictions{
-		{NotBefore: 100},
-		{NotBefore: 0},
-		{NotBefore: 300},
-		{NotBefore: 200},
-	}
-	expires := r.GetNotBefore()
-	var expected int64 = 0
-	if expected != expires {
-		t.Errorf("Expected %d, but got %d", expected, expires)
-	}
-}
diff --git a/internal/utils/issuerUtils/issuerUtilsCombineSubIss_test.go b/internal/utils/issuerUtils/issuerUtilsCombineSubIss_test.go
deleted file mode 100644
index 2996a7d3..00000000
--- a/internal/utils/issuerUtils/issuerUtilsCombineSubIss_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package issuerUtils
-
-import "testing"
-
-func TestCombineSubIssValid(t *testing.T) {
-	str := CombineSubIss("sub", "iss")
-	expected := "sub@iss"
-	if str != expected {
-		t.Errorf("Expected '%s', got '%s'", expected, str)
-	}
-}
-func TestCombineSubIssEmptyIss(t *testing.T) {
-	str := CombineSubIss("sub", "")
-	expected := ""
-	if str != expected {
-		t.Errorf("Expected '%s', got '%s'", expected, str)
-	}
-}
-func TestCombineSubIssEmptySub(t *testing.T) {
-	str := CombineSubIss("", "iss")
-	expected := ""
-	if str != expected {
-		t.Errorf("Expected '%s', got '%s'", expected, str)
-	}
-}
diff --git a/internal/utils/issuerUtils/issuerUtilsCompareIssuerURL_test.go b/internal/utils/issuerUtils/issuerUtilsCompareIssuerURL_test.go
deleted file mode 100644
index 988c972e..00000000
--- a/internal/utils/issuerUtils/issuerUtilsCompareIssuerURL_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package issuerUtils
-
-import "testing"
-
-func TestCompareIssuerURLBothEmpty(t *testing.T) {
-	if CompareIssuerURLs("", "") != true {
-		t.Errorf("Empty issuer urls should be equal")
-	}
-}
-func TestCompareIssuerURLOneEmpty(t *testing.T) {
-	a := "https://example.com"
-	b := ""
-	if CompareIssuerURLs(a, b) == true {
-		t.Errorf("An empty issuer url should not equal a non-empty")
-	}
-	if CompareIssuerURLs(b, a) == true {
-		t.Errorf("An empty issuer url should not equal a non-empty")
-	}
-}
-func TestCompareIssuerURLSame(t *testing.T) {
-	a := "https://example.com"
-	b := a
-	if CompareIssuerURLs(a, b) != true {
-		t.Errorf("Equal strings should be equal")
-	}
-	a = "https://example.com/"
-	b = a
-	if CompareIssuerURLs(a, b) != true {
-		t.Errorf("Equal strings should be equal")
-	}
-}
-
-func TestCompareIssuerURLDifferentSlash(t *testing.T) {
-	a := "https://example.com"
-	b := "https://example.com/"
-	if CompareIssuerURLs(a, b) != true {
-		t.Errorf("Issuer urls only differing in trailing slash should be equal")
-	}
-	if CompareIssuerURLs(b, a) != true {
-		t.Errorf("Issuer urls only differing in trailing slash should be equal")
-	}
-}
diff --git a/internal/utils/issuerUtils/issuerUtilsGetIssuerWithAndWithoutSlash_test.go b/internal/utils/issuerUtils/issuerUtilsGetIssuerWithAndWithoutSlash_test.go
deleted file mode 100644
index 809ad795..00000000
--- a/internal/utils/issuerUtils/issuerUtilsGetIssuerWithAndWithoutSlash_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package issuerUtils
-
-import "testing"
-
-func TestGetIssuerWithAndWithoutSlashEmpty(t *testing.T) {
-	iss0, iss1 := GetIssuerWithAndWithoutSlash("")
-	iss0Expected := ""
-	iss1Expected := "/"
-	if iss0 != iss0Expected {
-		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
-	}
-	if iss1 != iss1Expected {
-		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
-	}
-}
-
-func TestGetIssuerWithAndWithoutSlashTrailingSlash(t *testing.T) {
-	iss0, iss1 := GetIssuerWithAndWithoutSlash("https://example.com/")
-	iss0Expected := "https://example.com"
-	iss1Expected := "https://example.com/"
-	if iss0 != iss0Expected {
-		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
-	}
-	if iss1 != iss1Expected {
-		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
-	}
-}
-
-func TestGetIssuerWithAndWithoutSlashNoTrailingSlash(t *testing.T) {
-	iss0, iss1 := GetIssuerWithAndWithoutSlash("https://example.com")
-	iss0Expected := "https://example.com"
-	iss1Expected := "https://example.com/"
-	if iss0 != iss0Expected {
-		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
-	}
-	if iss1 != iss1Expected {
-		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
-	}
-}
diff --git a/internal/utils/issuerUtils/issuerUtils_test.go b/internal/utils/issuerUtils/issuerUtils_test.go
new file mode 100644
index 00000000..e220c8d6
--- /dev/null
+++ b/internal/utils/issuerUtils/issuerUtils_test.go
@@ -0,0 +1,97 @@
+package issuerUtils
+
+import "testing"
+
+func TestCombineSubIssValid(t *testing.T) {
+	str := CombineSubIss("sub", "iss")
+	expected := "sub@iss"
+	if str != expected {
+		t.Errorf("Expected '%s', got '%s'", expected, str)
+	}
+}
+func TestCombineSubIssEmptyIss(t *testing.T) {
+	str := CombineSubIss("sub", "")
+	expected := ""
+	if str != expected {
+		t.Errorf("Expected '%s', got '%s'", expected, str)
+	}
+}
+func TestCombineSubIssEmptySub(t *testing.T) {
+	str := CombineSubIss("", "iss")
+	expected := ""
+	if str != expected {
+		t.Errorf("Expected '%s', got '%s'", expected, str)
+	}
+}
+
+func TestCompareIssuerURLBothEmpty(t *testing.T) {
+	if CompareIssuerURLs("", "") != true {
+		t.Errorf("Empty issuer urls should be equal")
+	}
+}
+func TestCompareIssuerURLOneEmpty(t *testing.T) {
+	a := "https://example.com"
+	b := ""
+	if CompareIssuerURLs(a, b) == true {
+		t.Errorf("An empty issuer url should not equal a non-empty")
+	}
+	if CompareIssuerURLs(b, a) == true {
+		t.Errorf("An empty issuer url should not equal a non-empty")
+	}
+}
+func TestCompareIssuerURLSame(t *testing.T) {
+	a := "https://example.com"
+	b := a
+	if CompareIssuerURLs(a, b) != true {
+		t.Errorf("Equal strings should be equal")
+	}
+	a = "https://example.com/"
+	b = a
+	if CompareIssuerURLs(a, b) != true {
+		t.Errorf("Equal strings should be equal")
+	}
+}
+func TestCompareIssuerURLDifferentSlash(t *testing.T) {
+	a := "https://example.com"
+	b := "https://example.com/"
+	if CompareIssuerURLs(a, b) != true {
+		t.Errorf("Issuer urls only differing in trailing slash should be equal")
+	}
+	if CompareIssuerURLs(b, a) != true {
+		t.Errorf("Issuer urls only differing in trailing slash should be equal")
+	}
+}
+
+func TestGetIssuerWithAndWithoutSlashEmpty(t *testing.T) {
+	iss0, iss1 := GetIssuerWithAndWithoutSlash("")
+	iss0Expected := ""
+	iss1Expected := "/"
+	if iss0 != iss0Expected {
+		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
+	}
+	if iss1 != iss1Expected {
+		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
+	}
+}
+func TestGetIssuerWithAndWithoutSlashTrailingSlash(t *testing.T) {
+	iss0, iss1 := GetIssuerWithAndWithoutSlash("https://example.com/")
+	iss0Expected := "https://example.com"
+	iss1Expected := "https://example.com/"
+	if iss0 != iss0Expected {
+		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
+	}
+	if iss1 != iss1Expected {
+		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
+	}
+}
+func TestGetIssuerWithAndWithoutSlashNoTrailingSlash(t *testing.T) {
+	iss0, iss1 := GetIssuerWithAndWithoutSlash("https://example.com")
+	iss0Expected := "https://example.com"
+	iss1Expected := "https://example.com/"
+	if iss0 != iss0Expected {
+		t.Errorf("Iss0 Expected '%s', got '%s'", iss0Expected, iss0)
+	}
+	if iss1 != iss1Expected {
+		t.Errorf("Iss1 Expected '%s', got '%s'", iss1Expected, iss1)
+	}
+}
diff --git a/internal/utils/utilsCombineURLPath_test.go b/internal/utils/utilsCombineURLPath_test.go
deleted file mode 100644
index e9b63e6e..00000000
--- a/internal/utils/utilsCombineURLPath_test.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package utils
-
-import "testing"
-
-func testCombineURLs(t *testing.T, a, b, expected string) {
-	url := CombineURLPath(a, b)
-	if url != expected {
-		t.Errorf("Expected '%s', got '%s'", expected, url)
-	}
-}
-
-func TestCombineURLPathAllEmpty(t *testing.T) {
-	a := ""
-	b := ""
-	expected := ""
-	testCombineURLs(t, a, b, expected)
-}
-func TestCombineURLPathOneEmpty(t *testing.T) {
-	a := "https://example.com"
-	b := ""
-	expected := a
-	testCombineURLs(t, a, b, expected)
-	testCombineURLs(t, b, a, expected)
-}
-
-func TestCombineURLPathNoSlash(t *testing.T) {
-	a := "https://example.com"
-	b := "api"
-	expected := "https://example.com/api"
-	testCombineURLs(t, a, b, expected)
-}
-func TestCombineURLPathNoSlashTrailingSlash(t *testing.T) {
-	a := "https://example.com"
-	b := "api/"
-	expected := "https://example.com/api/"
-	testCombineURLs(t, a, b, expected)
-}
-
-func TestCombineURLPathOneSlashA(t *testing.T) {
-	a := "https://example.com/"
-	b := "api"
-	expected := "https://example.com/api"
-	testCombineURLs(t, a, b, expected)
-}
-func TestCombineURLPathOneSlashB(t *testing.T) {
-	a := "https://example.com"
-	b := "/api"
-	expected := "https://example.com/api"
-	testCombineURLs(t, a, b, expected)
-}
-
-func TestCombineURLPathBothSlash(t *testing.T) {
-	a := "https://example.com/"
-	b := "/api"
-	expected := "https://example.com/api"
-	testCombineURLs(t, a, b, expected)
-}
diff --git a/internal/utils/utilsIntersectSlices_test.go b/internal/utils/utilsIntersectSlices_test.go
deleted file mode 100644
index bcc36035..00000000
--- a/internal/utils/utilsIntersectSlices_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package utils
-
-import "testing"
-
-func fail(t *testing.T, expected, got []string) {
-	t.Errorf("Expected '%v', got '%v'", expected, got)
-}
-
-func testIntersectList(t *testing.T, a, b, expected []string) {
-	intersect := IntersectSlices(a, b)
-	if len(intersect) != len(expected) {
-		fail(t, expected, intersect)
-	}
-	for i, ee := range expected {
-		if ee != intersect[i] {
-			fail(t, expected, intersect)
-		}
-	}
-}
-
-func TestIntersectSlicesAllEmpty(t *testing.T) {
-	a := []string{}
-	b := []string{}
-	expected := []string{}
-	testIntersectList(t, a, b, expected)
-}
-func TestIntersectSlicesOneEmpty(t *testing.T) {
-	a := []string{}
-	b := []string{"not", "empty"}
-	expected := []string{}
-	testIntersectList(t, a, b, expected)
-	testIntersectList(t, b, a, expected)
-}
-func TestIntersectSlicesNoIntersection(t *testing.T) {
-	a := []string{"some", "values"}
-	b := []string{"completly", "different"}
-	expected := []string{}
-	testIntersectList(t, a, b, expected)
-	testIntersectList(t, b, a, expected)
-}
-func TestIntersectSlicesSame(t *testing.T) {
-	a := []string{"some", "values"}
-	testIntersectList(t, a, a, a)
-}
-func TestIntersectSlicesSomeIntersection(t *testing.T) {
-	a := []string{"some", "values"}
-	b := []string{"some", "different"}
-	expected := []string{"some"}
-	testIntersectList(t, a, b, expected)
-	testIntersectList(t, b, a, expected)
-}
-func TestIntersectSlicesSubSet(t *testing.T) {
-	a := []string{"some", "values"}
-	b := []string{"some", "more", "values"}
-	expected := []string{"some", "values"}
-	testIntersectList(t, a, b, expected)
-	testIntersectList(t, b, a, expected)
-}
diff --git a/internal/utils/utilsIsSubSet_test.go b/internal/utils/utilsIsSubSet_test.go
deleted file mode 100644
index 2f2dcfd1..00000000
--- a/internal/utils/utilsIsSubSet_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package utils
-
-import "testing"
-
-func testIsSubSet(t *testing.T, a, b []string, expected bool) {
-	ok := IsSubSet(a, b)
-	if ok != expected {
-		if expected {
-			t.Errorf("Actually '%v' is a subset of '%v'", a, b)
-		} else {
-			t.Errorf("Actually '%v' is not a subset of '%v'", a, b)
-		}
-	}
-}
-
-func TestIsSubSetAllEmpty(t *testing.T) {
-	a := []string{}
-	b := []string{}
-	testIsSubSet(t, a, b, true)
-}
-func TestIsSubSetOneEmpty(t *testing.T) {
-	a := []string{}
-	b := []string{"some", "values"}
-	testIsSubSet(t, a, b, true)
-	testIsSubSet(t, b, a, false)
-}
-func TestIsSubSetSubset(t *testing.T) {
-	a := []string{"some"}
-	b := []string{"some", "values"}
-	testIsSubSet(t, a, b, true)
-	testIsSubSet(t, b, a, false)
-}
-func TestIsSubSetDistinct(t *testing.T) {
-	a := []string{"other"}
-	b := []string{"some", "values"}
-	testIsSubSet(t, a, b, false)
-	testIsSubSet(t, b, a, false)
-}
diff --git a/internal/utils/utilsSliceUnion_test.go b/internal/utils/utilsSliceUnion_test.go
deleted file mode 100644
index bff50527..00000000
--- a/internal/utils/utilsSliceUnion_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package utils
-
-import "testing"
-
-func TestSliceUnion_Empty(t *testing.T) {
-	a := []string{}
-	b := []string{}
-	exp := []string{}
-	u := SliceUnion(a, b)
-	checkSlice(t, u, exp)
-	u = SliceUnion(b, a)
-	checkSlice(t, u, exp)
-}
-
-func TestSliceUnion_OneEmpty(t *testing.T) {
-	a := []string{}
-	b := []string{"a", "b"}
-	exp := []string{"a", "b"}
-	u := SliceUnion(a, b)
-	checkSlice(t, u, exp)
-	u = SliceUnion(b, a)
-	checkSlice(t, u, exp)
-}
-
-func TestSliceUnion_Same(t *testing.T) {
-	a := []string{"a", "b"}
-	b := []string{"a", "b"}
-	exp := []string{"a", "b"}
-	u := SliceUnion(a, b)
-	checkSlice(t, u, exp)
-	u = SliceUnion(b, a)
-	checkSlice(t, u, exp)
-}
-
-func TestSliceUnion_Distinct(t *testing.T) {
-	a := []string{"a", "b"}
-	b := []string{"c", "d"}
-	exp := []string{"a", "b", "c", "d"}
-	u := SliceUnion(a, b)
-	checkSlice(t, u, exp)
-	exp = []string{"c", "d", "a", "b"}
-	u = SliceUnion(b, a)
-	checkSlice(t, u, exp)
-}
-
-func TestSliceUnion_Mixed(t *testing.T) {
-	a := []string{"a", "b", "c"}
-	b := []string{"c", "b", "d"}
-	exp := []string{"a", "b", "c", "d"}
-	u := SliceUnion(a, b)
-	checkSlice(t, u, exp)
-	exp = []string{"c", "b", "d", "a"}
-	u = SliceUnion(b, a)
-	checkSlice(t, u, exp)
-}
diff --git a/internal/utils/utilsStringInSlice_test.go b/internal/utils/utilsStringInSlice_test.go
deleted file mode 100644
index e4af8113..00000000
--- a/internal/utils/utilsStringInSlice_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package utils
-
-import "testing"
-
-func TestStringInSliceFirstPosition(t *testing.T) {
-	str := "key"
-	slice := []string{str, "other", "another"}
-	found := StringInSlice(str, slice)
-	if found != true {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
-func TestStringInSliceLastPosition(t *testing.T) {
-	str := "key"
-	slice := []string{"other", "another", str}
-	found := StringInSlice(str, slice)
-	if found != true {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
-func TestStringInSliceMidPosition(t *testing.T) {
-	str := "key"
-	slice := []string{"other", str, "another"}
-	found := StringInSlice(str, slice)
-	if found != true {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
-func TestStringInSliceOnly(t *testing.T) {
-	str := "key"
-	slice := []string{str}
-	found := StringInSlice(str, slice)
-	if found != true {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
-func TestStringInSliceEmpty(t *testing.T) {
-	str := "key"
-	slice := []string{}
-	found := StringInSlice(str, slice)
-	if found != false {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
-func TestStringInSliceNotFound(t *testing.T) {
-	str := "key"
-	slice := []string{"only", "other", "strings"}
-	found := StringInSlice(str, slice)
-	if found != false {
-		t.Errorf("'%s' not found in slice '%v'", str, slice)
-	}
-}
diff --git a/internal/utils/utilsUniqueSlice_test.go b/internal/utils/utilsUniqueSlice_test.go
deleted file mode 100644
index 036e07a7..00000000
--- a/internal/utils/utilsUniqueSlice_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package utils
-
-import "testing"
-
-func failSlice(t *testing.T, a, exp []string) {
-	t.Errorf("Expected '%+v', but go '%+v'", exp, a)
-}
-
-func checkSlice(t *testing.T, a, exp []string) {
-	if len(a) != len(exp) {
-		failSlice(t, a, exp)
-		return
-	}
-	for i, e := range exp {
-		if e != a[i] {
-			failSlice(t, a, exp)
-			return
-		}
-	}
-}
-
-func TestUniqueSlice_Empty(t *testing.T) {
-	a := []string{}
-	exp := []string{}
-	u := UniqueSlice(a)
-	checkSlice(t, u, exp)
-}
-
-func TestUniqueSlice_Unique(t *testing.T) {
-	a := []string{"a", "b", "c"}
-	exp := []string{"a", "b", "c"}
-	u := UniqueSlice(a)
-	checkSlice(t, u, exp)
-}
-
-func TestUniqueSlice_Duplicates(t *testing.T) {
-	a := []string{"a", "b", "a", "c", "c", "d", "c", "e"}
-	exp := []string{"a", "b", "c", "d", "e"}
-	u := UniqueSlice(a)
-	checkSlice(t, u, exp)
-}
diff --git a/internal/utils/utils_test.go b/internal/utils/utils_test.go
new file mode 100644
index 00000000..85e704c3
--- /dev/null
+++ b/internal/utils/utils_test.go
@@ -0,0 +1,272 @@
+package utils
+
+import "testing"
+
+func fail(t *testing.T, expected, got []string) {
+	t.Errorf("Expected '%v', got '%v'", expected, got)
+}
+
+func testCombineURLs(t *testing.T, a, b, expected string) {
+	url := CombineURLPath(a, b)
+	if url != expected {
+		t.Errorf("Expected '%s', got '%s'", expected, url)
+	}
+}
+func TestCombineURLPathAllEmpty(t *testing.T) {
+	a := ""
+	b := ""
+	expected := ""
+	testCombineURLs(t, a, b, expected)
+}
+func TestCombineURLPathOneEmpty(t *testing.T) {
+	a := "https://example.com"
+	b := ""
+	expected := a
+	testCombineURLs(t, a, b, expected)
+	testCombineURLs(t, b, a, expected)
+}
+func TestCombineURLPathNoSlash(t *testing.T) {
+	a := "https://example.com"
+	b := "api"
+	expected := "https://example.com/api"
+	testCombineURLs(t, a, b, expected)
+}
+func TestCombineURLPathNoSlashTrailingSlash(t *testing.T) {
+	a := "https://example.com"
+	b := "api/"
+	expected := "https://example.com/api/"
+	testCombineURLs(t, a, b, expected)
+}
+func TestCombineURLPathOneSlashA(t *testing.T) {
+	a := "https://example.com/"
+	b := "api"
+	expected := "https://example.com/api"
+	testCombineURLs(t, a, b, expected)
+}
+func TestCombineURLPathOneSlashB(t *testing.T) {
+	a := "https://example.com"
+	b := "/api"
+	expected := "https://example.com/api"
+	testCombineURLs(t, a, b, expected)
+}
+func TestCombineURLPathBothSlash(t *testing.T) {
+	a := "https://example.com/"
+	b := "/api"
+	expected := "https://example.com/api"
+	testCombineURLs(t, a, b, expected)
+}
+
+func testIntersectList(t *testing.T, a, b, expected []string) {
+	intersect := IntersectSlices(a, b)
+	if len(intersect) != len(expected) {
+		fail(t, expected, intersect)
+	}
+	for i, ee := range expected {
+		if ee != intersect[i] {
+			fail(t, expected, intersect)
+		}
+	}
+}
+func TestIntersectSlicesAllEmpty(t *testing.T) {
+	a := []string{}
+	b := []string{}
+	expected := []string{}
+	testIntersectList(t, a, b, expected)
+}
+func TestIntersectSlicesOneEmpty(t *testing.T) {
+	a := []string{}
+	b := []string{"not", "empty"}
+	expected := []string{}
+	testIntersectList(t, a, b, expected)
+	testIntersectList(t, b, a, expected)
+}
+func TestIntersectSlicesNoIntersection(t *testing.T) {
+	a := []string{"some", "values"}
+	b := []string{"completly", "different"}
+	expected := []string{}
+	testIntersectList(t, a, b, expected)
+	testIntersectList(t, b, a, expected)
+}
+func TestIntersectSlicesSame(t *testing.T) {
+	a := []string{"some", "values"}
+	testIntersectList(t, a, a, a)
+}
+func TestIntersectSlicesSomeIntersection(t *testing.T) {
+	a := []string{"some", "values"}
+	b := []string{"some", "different"}
+	expected := []string{"some"}
+	testIntersectList(t, a, b, expected)
+	testIntersectList(t, b, a, expected)
+}
+func TestIntersectSlicesSubSet(t *testing.T) {
+	a := []string{"some", "values"}
+	b := []string{"some", "more", "values"}
+	expected := []string{"some", "values"}
+	testIntersectList(t, a, b, expected)
+	testIntersectList(t, b, a, expected)
+}
+
+func testIsSubSet(t *testing.T, a, b []string, expected bool) {
+	ok := IsSubSet(a, b)
+	if ok != expected {
+		if expected {
+			t.Errorf("Actually '%v' is a subset of '%v'", a, b)
+		} else {
+			t.Errorf("Actually '%v' is not a subset of '%v'", a, b)
+		}
+	}
+}
+func TestIsSubSetAllEmpty(t *testing.T) {
+	a := []string{}
+	b := []string{}
+	testIsSubSet(t, a, b, true)
+}
+func TestIsSubSetOneEmpty(t *testing.T) {
+	a := []string{}
+	b := []string{"some", "values"}
+	testIsSubSet(t, a, b, true)
+	testIsSubSet(t, b, a, false)
+}
+func TestIsSubSetSubset(t *testing.T) {
+	a := []string{"some"}
+	b := []string{"some", "values"}
+	testIsSubSet(t, a, b, true)
+	testIsSubSet(t, b, a, false)
+}
+func TestIsSubSetDistinct(t *testing.T) {
+	a := []string{"other"}
+	b := []string{"some", "values"}
+	testIsSubSet(t, a, b, false)
+	testIsSubSet(t, b, a, false)
+}
+
+func TestSliceUnion_Empty(t *testing.T) {
+	a := []string{}
+	b := []string{}
+	exp := []string{}
+	u := SliceUnion(a, b)
+	checkSlice(t, u, exp)
+	u = SliceUnion(b, a)
+	checkSlice(t, u, exp)
+}
+func TestSliceUnion_OneEmpty(t *testing.T) {
+	a := []string{}
+	b := []string{"a", "b"}
+	exp := []string{"a", "b"}
+	u := SliceUnion(a, b)
+	checkSlice(t, u, exp)
+	u = SliceUnion(b, a)
+	checkSlice(t, u, exp)
+}
+func TestSliceUnion_Same(t *testing.T) {
+	a := []string{"a", "b"}
+	b := []string{"a", "b"}
+	exp := []string{"a", "b"}
+	u := SliceUnion(a, b)
+	checkSlice(t, u, exp)
+	u = SliceUnion(b, a)
+	checkSlice(t, u, exp)
+}
+func TestSliceUnion_Distinct(t *testing.T) {
+	a := []string{"a", "b"}
+	b := []string{"c", "d"}
+	exp := []string{"a", "b", "c", "d"}
+	u := SliceUnion(a, b)
+	checkSlice(t, u, exp)
+	exp = []string{"c", "d", "a", "b"}
+	u = SliceUnion(b, a)
+	checkSlice(t, u, exp)
+}
+func TestSliceUnion_Mixed(t *testing.T) {
+	a := []string{"a", "b", "c"}
+	b := []string{"c", "b", "d"}
+	exp := []string{"a", "b", "c", "d"}
+	u := SliceUnion(a, b)
+	checkSlice(t, u, exp)
+	exp = []string{"c", "b", "d", "a"}
+	u = SliceUnion(b, a)
+	checkSlice(t, u, exp)
+}
+
+func TestStringInSliceFirstPosition(t *testing.T) {
+	str := "key"
+	slice := []string{str, "other", "another"}
+	found := StringInSlice(str, slice)
+	if found != true {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+func TestStringInSliceLastPosition(t *testing.T) {
+	str := "key"
+	slice := []string{"other", "another", str}
+	found := StringInSlice(str, slice)
+	if found != true {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+func TestStringInSliceMidPosition(t *testing.T) {
+	str := "key"
+	slice := []string{"other", str, "another"}
+	found := StringInSlice(str, slice)
+	if found != true {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+func TestStringInSliceOnly(t *testing.T) {
+	str := "key"
+	slice := []string{str}
+	found := StringInSlice(str, slice)
+	if found != true {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+func TestStringInSliceEmpty(t *testing.T) {
+	str := "key"
+	slice := []string{}
+	found := StringInSlice(str, slice)
+	if found != false {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+func TestStringInSliceNotFound(t *testing.T) {
+	str := "key"
+	slice := []string{"only", "other", "strings"}
+	found := StringInSlice(str, slice)
+	if found != false {
+		t.Errorf("'%s' not found in slice '%v'", str, slice)
+	}
+}
+
+func failSlice(t *testing.T, a, exp []string) {
+	t.Errorf("Expected '%+v', but go '%+v'", exp, a)
+}
+func checkSlice(t *testing.T, a, exp []string) {
+	if len(a) != len(exp) {
+		failSlice(t, a, exp)
+		return
+	}
+	for i, e := range exp {
+		if e != a[i] {
+			failSlice(t, a, exp)
+			return
+		}
+	}
+}
+func TestUniqueSlice_Empty(t *testing.T) {
+	a := []string{}
+	exp := []string{}
+	u := UniqueSlice(a)
+	checkSlice(t, u, exp)
+}
+func TestUniqueSlice_Unique(t *testing.T) {
+	a := []string{"a", "b", "c"}
+	exp := []string{"a", "b", "c"}
+	u := UniqueSlice(a)
+	checkSlice(t, u, exp)
+}
+func TestUniqueSlice_Duplicates(t *testing.T) {
+	a := []string{"a", "b", "a", "c", "c", "d", "c", "e"}
+	exp := []string{"a", "b", "c", "d", "e"}
+	u := UniqueSlice(a)
+	checkSlice(t, u, exp)
+}
-- 
GitLab