diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/cvss/v2key_test.go | 98 | ||||
| -rw-r--r-- | internal/cvss/v2metric.go | 2 | ||||
| -rw-r--r-- | internal/cvss/v2metric_test.go | 267 | ||||
| -rw-r--r-- | internal/cvss/v2vector.go | 2 | ||||
| -rw-r--r-- | internal/cvss/v2vector_test.go | 48 | ||||
| -rw-r--r-- | internal/cvss/v30vector_test.go | 49 | ||||
| -rw-r--r-- | internal/cvss/v31vector_test.go | 52 | ||||
| -rw-r--r-- | internal/cvss/v3key_test.go | 124 | 
8 files changed, 622 insertions, 20 deletions
| diff --git a/internal/cvss/v2key_test.go b/internal/cvss/v2key_test.go new file mode 100644 index 0000000..76a3d79 --- /dev/null +++ b/internal/cvss/v2key_test.go @@ -0,0 +1,98 @@ +package cvss + +import "testing" + +func TestV2KeyString(t *testing.T) { +  tests := []struct { +    key v2Key +    exp string +  } { +    { v2AccessVector, "AV" }, +    { v2AccessComplexity, "AC" }, +    { v2Authentication, "Au" }, +    { v2ConfidentialityImpact, "C" }, +    { v2IntegrityImpact, "I" }, +    { v2AvailabilityImpact, "A" }, +    { v2Exploitability, "E" }, +    { v2RemediationLevel, "RL" }, +    { v2ReportConfidence, "RC" }, +    { v2CollateralDamagePotential, "CDP" }, +    { v2TargetDistribution, "TD" }, +    { v2ConfidentialityRequirement, "CR" }, +    { v2IntegrityRequirement, "IR" }, +    { v2AvailabilityRequirement, "AR" }, + +    { v2Key(255), "v2Key(255)" }, +  } + +  for _, test := range(tests) { +    t.Run(test.exp, func(t *testing.T) { +      got := test.key.String() +      if got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } +    }) +  } +} + +func TestV2KeyName(t *testing.T) { +  tests := []struct { +    key v2Key +    exp string +  } { +    { v2AccessVector, "Access Vector" }, +    { v2AccessComplexity, "Access Complexity" }, +    { v2Authentication, "Authentication" }, +    { v2ConfidentialityImpact, "Confidentiality Impact" }, +    { v2IntegrityImpact, "Integrity Impact" }, +    { v2AvailabilityImpact, "Availability Impact" }, +    { v2Exploitability, "Exploitability" }, +    { v2RemediationLevel, "Remediation Level" }, +    { v2ReportConfidence, "Report Confidence" }, +    { v2CollateralDamagePotential, "Collateral Damage Potential" }, +    { v2TargetDistribution, "Target Distribution" }, +    { v2ConfidentialityRequirement, "Confidentiality Requirement" }, +    { v2IntegrityRequirement, "Integrity Requirement" }, +    { v2AvailabilityRequirement, "Availability Requirement" }, +  } + +  for _, test := range(tests) { +    t.Run(test.exp, func(t *testing.T) { +      got := test.key.Name() +      if got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } +    }) +  } +} + +func TestV2KeyCategory(t *testing.T) { +  tests := []struct { +    key v2Key +    exp Category +  } { +    { v2AccessVector, Base }, +    { v2AccessComplexity, Base }, +    { v2Authentication, Base }, +    { v2ConfidentialityImpact, Base }, +    { v2IntegrityImpact, Base }, +    { v2AvailabilityImpact, Base }, +    { v2Exploitability, Temporal }, +    { v2RemediationLevel, Temporal }, +    { v2ReportConfidence, Temporal }, +    { v2CollateralDamagePotential, Environmental }, +    { v2TargetDistribution, Environmental}, +    { v2ConfidentialityRequirement, Environmental}, +    { v2IntegrityRequirement, Environmental}, +    { v2AvailabilityRequirement, Environmental}, +  } + +  for _, test := range(tests) { +    t.Run(test.key.String(), func(t *testing.T) { +      got := test.key.Category() +      if got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } +    }) +  } +} diff --git a/internal/cvss/v2metric.go b/internal/cvss/v2metric.go index de8b52b..a80cf8a 100644 --- a/internal/cvss/v2metric.go +++ b/internal/cvss/v2metric.go @@ -223,7 +223,7 @@ var v2MetricStrLut = map[string]v2Metric {  }  // Convert string to CVSS 2.0 metric. -func getV2MetricFromString(s string) (v2Metric, error) { +func getV2Metric(s string) (v2Metric, error) {    // get metric    m, ok := v2MetricStrLut[s]    if !ok { diff --git a/internal/cvss/v2metric_test.go b/internal/cvss/v2metric_test.go new file mode 100644 index 0000000..b17d2ed --- /dev/null +++ b/internal/cvss/v2metric_test.go @@ -0,0 +1,267 @@ +package cvss + +import "testing" + +func TestGetV2Metric(t *testing.T) { +  tests := []struct { +    val string +    exp v2Metric +    ok  bool +  } { +    { "AV:N", v2AVNetwork, true }, +    { "AV:A", v2AVAdjacentNetwork, true }, +    { "AV:L", v2AVLocal, true }, + +    { "AC:L", v2ACLow, true }, +    { "AC:M", v2ACMedium, true }, +    { "AC:H", v2ACHigh, true }, + +    { "Au:M", v2AuMultiple, true }, +    { "Au:S", v2AuSingle, true }, +    { "Au:N", v2AuNone, true }, + +    { "C:N", v2CNone, true }, +    { "C:P", v2CPartial, true }, +    { "C:C", v2CComplete, true }, + +    { "I:N", v2INone, true }, +    { "I:P", v2IPartial, true }, +    { "I:C", v2IComplete, true }, + +    { "A:N", v2ANone, true }, +    { "A:P", v2APartial, true }, +    { "A:C", v2AComplete, true }, + +    { "E:ND", v2ENotDefined, true }, +    { "E:U", v2EUnproven, true }, +    { "E:POC", v2EProofOfConcept, true }, +    { "E:F", v2EFunctional, true }, +    { "E:H", v2EHigh, true }, + +    { "RL:OF", v2RLOfficialFix, true }, +    { "RL:TF", v2RLTemporaryFix, true }, +    { "RL:W", v2RLWorkaround, true }, +    { "RL:U", v2RLUnavailable, true }, +    { "RL:ND", v2RLNotDefined, true }, + +    { "RC:UC", v2RCUnconfirmed, true }, +    { "RC:UR", v2RCUncorroborated, true }, +    { "RC:C", v2RCConfirmed, true }, +    { "RC:ND", v2RCNotDefined, true }, + +    { "CDP:N", v2CDPNone, true }, +    { "CDP:L", v2CDPLow, true }, +    { "CDP:LM", v2CDPLowMedium, true }, +    { "CDP:MH", v2CDPMediumHigh, true }, +    { "CDP:H", v2CDPHigh, true }, +    { "CDP:ND", v2CDPNotDefined, true }, + +    { "TD:N", v2TDNone, true }, +    { "TD:L", v2TDLow, true }, +    { "TD:M", v2TDMedium, true }, +    { "TD:H", v2TDHigh, true }, +    { "TD:ND", v2TDNotDefined, true }, + +    { "CR:L", v2CRLow, true }, +    { "CR:M", v2CRMedium, true }, +    { "CR:H", v2CRHigh, true }, +    { "CR:ND", v2CRNotDefined, true }, + +    { "IR:L", v2IRLow, true }, +    { "IR:M", v2IRMedium, true }, +    { "IR:H", v2IRHigh, true }, +    { "IR:ND", v2IRNotDefined, true }, + +    { "AR:L", v2ARLow, true }, +    { "AR:M", v2ARMedium, true }, +    { "AR:H", v2ARHigh, true }, +    { "AR:ND", v2ARNotDefined, true }, + +    { "asdf", v2InvalidMetric, false }, +  } + +  for _, test := range(tests) { +    t.Run(test.val, func(t *testing.T) { +      got, err := getV2Metric(test.val) +      if test.ok && err == nil && got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } else if test.ok && err != nil { +        t.Error(err) +      } else if !test.ok && err == nil { +        t.Errorf("got: \"%s\", exp: error", got) +      } +    }) +  } +} + +func TestGetV2MetricKey(t *testing.T) { +  tests := []struct { +    val v2Metric +    exp v2Key +  } { +    { v2AVNetwork, v2AccessVector }, +    { v2AVAdjacentNetwork, v2AccessVector }, +    { v2AVLocal, v2AccessVector }, + +    { v2ACLow, v2AccessComplexity }, +    { v2ACMedium, v2AccessComplexity }, +    { v2ACHigh, v2AccessComplexity }, + +    { v2AuMultiple, v2Authentication }, +    { v2AuSingle, v2Authentication }, +    { v2AuNone, v2Authentication }, + +    { v2CNone, v2ConfidentialityImpact }, +    { v2CPartial, v2ConfidentialityImpact }, +    { v2CComplete, v2ConfidentialityImpact }, + +    { v2INone, v2IntegrityImpact }, +    { v2IPartial, v2IntegrityImpact }, +    { v2IComplete, v2IntegrityImpact }, + +    { v2ANone, v2AvailabilityImpact }, +    { v2APartial, v2AvailabilityImpact }, +    { v2AComplete, v2AvailabilityImpact }, + +    { v2ENotDefined, v2Exploitability }, +    { v2EUnproven, v2Exploitability }, +    { v2EProofOfConcept, v2Exploitability }, +    { v2EFunctional, v2Exploitability }, +    { v2EHigh, v2Exploitability }, + +    { v2RLOfficialFix, v2RemediationLevel }, +    { v2RLTemporaryFix, v2RemediationLevel }, +    { v2RLWorkaround, v2RemediationLevel }, +    { v2RLUnavailable, v2RemediationLevel }, +    { v2RLNotDefined, v2RemediationLevel }, + +    { v2RCUnconfirmed, v2ReportConfidence }, +    { v2RCUncorroborated, v2ReportConfidence }, +    { v2RCConfirmed, v2ReportConfidence }, +    { v2RCNotDefined, v2ReportConfidence }, + +    { v2CDPNone, v2CollateralDamagePotential }, +    { v2CDPLow, v2CollateralDamagePotential }, +    { v2CDPLowMedium, v2CollateralDamagePotential }, +    { v2CDPMediumHigh, v2CollateralDamagePotential }, +    { v2CDPHigh, v2CollateralDamagePotential }, +    { v2CDPNotDefined, v2CollateralDamagePotential }, + +    { v2TDNone, v2TargetDistribution }, +    { v2TDLow, v2TargetDistribution }, +    { v2TDMedium, v2TargetDistribution }, +    { v2TDHigh, v2TargetDistribution }, +    { v2TDNotDefined, v2TargetDistribution }, + +    { v2CRLow, v2ConfidentialityRequirement }, +    { v2CRMedium, v2ConfidentialityRequirement }, +    { v2CRHigh, v2ConfidentialityRequirement }, +    { v2CRNotDefined, v2ConfidentialityRequirement }, + +    { v2IRLow, v2IntegrityRequirement }, +    { v2IRMedium, v2IntegrityRequirement }, +    { v2IRHigh, v2IntegrityRequirement }, +    { v2IRNotDefined, v2IntegrityRequirement }, + +    { v2ARLow, v2AvailabilityRequirement }, +    { v2ARMedium, v2AvailabilityRequirement }, +    { v2ARHigh, v2AvailabilityRequirement }, +    { v2ARNotDefined, v2AvailabilityRequirement }, +  } + +  for _, test := range(tests) { +    t.Run(test.val.String(), func(t *testing.T) { +      got := test.val.Key() +      if got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } +    }) +  } +} + +func TestV2MetricString(t *testing.T) { +  tests := []struct { +    val v2Metric +    exp string +  } { +    { v2AVNetwork, "AV:N" }, +    { v2AVAdjacentNetwork, "AV:A" }, +    { v2AVLocal, "AV:L" }, + +    { v2ACLow, "AC:L" }, +    { v2ACMedium, "AC:M" }, +    { v2ACHigh, "AC:H" }, + +    { v2AuMultiple, "Au:M" }, +    { v2AuSingle, "Au:S" }, +    { v2AuNone, "Au:N" }, + +    { v2CNone, "C:N" }, +    { v2CPartial, "C:P" }, +    { v2CComplete, "C:C" }, + +    { v2INone, "I:N" }, +    { v2IPartial, "I:P" }, +    { v2IComplete, "I:C" }, + +    { v2ANone, "A:N" }, +    { v2APartial, "A:P" }, +    { v2AComplete, "A:C" }, + +    { v2ENotDefined, "E:ND" }, +    { v2EUnproven, "E:U" }, +    { v2EProofOfConcept, "E:POC" }, +    { v2EFunctional, "E:F" }, +    { v2EHigh, "E:H" }, + +    { v2RLOfficialFix, "RL:OF" }, +    { v2RLTemporaryFix, "RL:TF" }, +    { v2RLWorkaround, "RL:W" }, +    { v2RLUnavailable, "RL:U" }, +    { v2RLNotDefined, "RL:ND" }, + +    { v2RCUnconfirmed, "RC:UC" }, +    { v2RCUncorroborated, "RC:UR" }, +    { v2RCConfirmed, "RC:C" }, +    { v2RCNotDefined, "RC:ND" }, + +    { v2CDPNone, "CDP:N" }, +    { v2CDPLow, "CDP:L" }, +    { v2CDPLowMedium, "CDP:LM" }, +    { v2CDPMediumHigh, "CDP:MH" }, +    { v2CDPHigh, "CDP:H" }, +    { v2CDPNotDefined, "CDP:ND" }, + +    { v2TDNone, "TD:N" }, +    { v2TDLow, "TD:L" }, +    { v2TDMedium, "TD:M" }, +    { v2TDHigh, "TD:H" }, +    { v2TDNotDefined, "TD:ND" }, + +    { v2CRLow, "CR:L" }, +    { v2CRMedium, "CR:M" }, +    { v2CRHigh, "CR:H" }, +    { v2CRNotDefined, "CR:ND" }, + +    { v2IRLow, "IR:L" }, +    { v2IRMedium, "IR:M" }, +    { v2IRHigh, "IR:H" }, +    { v2IRNotDefined, "IR:ND" }, + +    { v2ARLow, "AR:L" }, +    { v2ARMedium, "AR:M" }, +    { v2ARHigh, "AR:H" }, +    { v2ARNotDefined, "AR:ND" }, + +    { v2Metric(255), "v2Metric(255)" }, +  } + +  for _, test := range(tests) { +    t.Run(test.val.String(), func(t *testing.T) { +      got := test.val.String() +      if got != test.exp { +        t.Errorf("got: \"%s\", exp: \"%s\"", got, test.exp) +      } +    }) +  } +} diff --git a/internal/cvss/v2vector.go b/internal/cvss/v2vector.go index efa2444..909bca6 100644 --- a/internal/cvss/v2vector.go +++ b/internal/cvss/v2vector.go @@ -47,7 +47,7 @@ func newV2Vector(s string) (Vector, error) {    // walk metric strings    for i, ms := range(strs) {      // convert string to vector -    m, err := getV2MetricFromString(ms) +    m, err := getV2Metric(ms)      if err != nil {        return nil, err      } diff --git a/internal/cvss/v2vector_test.go b/internal/cvss/v2vector_test.go index 3ef4194..a943957 100644 --- a/internal/cvss/v2vector_test.go +++ b/internal/cvss/v2vector_test.go @@ -1,17 +1,51 @@  package cvss -import "testing" +import ( +  "testing" +) -// test v2 vector -var testCvssV2 = "AV:L/AC:L/Au:N/C:N/I:N/A:P" - -// Test cvss v2 parser +// Test cvss v2  func TestCvssV2Parser(t *testing.T) { +  // test v2 vector +  test := "AV:L/AC:L/Au:N/C:N/I:N/A:P" +  expMetrics := []string { "AV:L", "AC:L", "Au:N", "C:N", "I:N", "A:P" } +    t.Run("TestV2Parser", func(t *testing.T) { -    // parse vector, check for error -    _, err := NewVector(testCvssV2) +    // parse vector +    vec, err := NewVector(test)      if err != nil {        t.Error(err) +      return +    } + +    // check version +    if vec.Version() != V20 { +      t.Errorf("got %s, exp %s", vec.Version(), V20) +      return +    } + +    for i, m := range(vec.Metrics()) { +      got := m.String() +      if got != expMetrics[i] { +        t.Errorf("got %s, exp %s", got, expMetrics[i]) +      }      }    })  } + +// Test cvss v2 +func TestInvalidV2Vector(t *testing.T) { +  // test invalid vector +  test := "AV:L/junk/Au:N/C:N/I:N/A:P" +  exp := "invalid CVSS 2.0 metric: junk" + +  // parse vector +  got, err := NewVector(test) +  if err != nil && err.Error() != exp { +    t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err) +    return +  } else if err == nil { +    t.Errorf("got \"%s\", exp badMetric", got) +    return +  } +} diff --git a/internal/cvss/v30vector_test.go b/internal/cvss/v30vector_test.go new file mode 100644 index 0000000..fae3436 --- /dev/null +++ b/internal/cvss/v30vector_test.go @@ -0,0 +1,49 @@ +package cvss + +import ( +  "testing" +) + +func TestV30Vector(t *testing.T) { +  // test v3 vector +  test := "CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N" +  expMetrics := []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" } + +  t.Run("TestV30Vector", func(t *testing.T) { +    // parse vector +    vec, err := NewVector(test) +    if err != nil { +      t.Error(err) +      return +    } + +    // check version +    if vec.Version() != V30 { +      t.Errorf("got %s, exp %s", vec.Version(), V30) +      return +    } + +    for i, m := range(vec.Metrics()) { +      got := m.String() +      if got != expMetrics[i] { +        t.Errorf("got %s, exp %s", got, expMetrics[i]) +      } +    } +  }) +} + +func TestInvalidV30Vector(t *testing.T) { +  // test invalid vector +  test := "CVSS:3.0/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N" +  exp := "invalid CVSS 3.0 metric: junk" + +  // parse vector +  got, err := NewVector(test) +  if err != nil && err.Error() != exp { +    t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err) +    return +  } else if err == nil { +    t.Errorf("got \"%s\", exp badMetric", got) +    return +  } +} diff --git a/internal/cvss/v31vector_test.go b/internal/cvss/v31vector_test.go index 8340123..ba82edb 100644 --- a/internal/cvss/v31vector_test.go +++ b/internal/cvss/v31vector_test.go @@ -1,19 +1,49 @@  package cvss -import "testing" +import ( +  "testing" +) -// test cvss v3.1 vector -var testCvssV3 = "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H" +func TestV31Vector(t *testing.T) { +  // test v3 vector +  test := "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N" +  expMetrics := []string { "AV:L", "AC:H", "PR:L", "UI:N", "S:U", "C:H", "I:N", "A:N" } -// Test CVSS v3 parser. -func TestCvssV3Parser(t *testing.T) { -  t.Run("TestV3", func(t *testing.T) { -    // parse vector, check for error -    if _, err := NewVector(testCvssV3); err != nil { -      t.Fatal(err) +  t.Run("TestV31Vector", func(t *testing.T) { +    // parse vector +    vec, err := NewVector(test) +    if err != nil { +      t.Error(err) +      return +    } + +    // check version +    if vec.Version() != V31 { +      t.Errorf("got %s, exp %s", vec.Version(), V31) +      return +    } + +    for i, m := range(vec.Metrics()) { +      got := m.String() +      if got != expMetrics[i] { +        t.Errorf("got %s, exp %s", got, expMetrics[i]) +      }      }    }) +} + +func TestInvalidV31Vector(t *testing.T) { +  // test invalid vector +  test := "CVSS:3.1/AV:L/junk/PR:L/UI:N/S:U/C:H/I:N/A:N" +  exp := "invalid CVSS 3.1 metric: junk" -  // fmt.Println(v.Metrics()) -  // fmt.Println(v) +  // parse vector +  got, err := NewVector(test) +  if err != nil && err.Error() != exp { +    t.Errorf("got \"%s\", exp \"%s\"", err.Error(), err) +    return +  } else if err == nil { +    t.Errorf("got \"%s\", exp badMetric", got) +    return +  }  } diff --git a/internal/cvss/v3key_test.go b/internal/cvss/v3key_test.go new file mode 100644 index 0000000..ccf2b8f --- /dev/null +++ b/internal/cvss/v3key_test.go @@ -0,0 +1,124 @@ +package cvss + +import ( +  "testing" +) + +func TestV3KeyString(t *testing.T) { +  tests := []struct { +    val v3Key +    exp string +  } { +    { v3AttackVector, "AV" }, +    { v3AttackComplexity, "AC" }, +    { v3PrivilegesRequired, "PR" }, +    { v3UserInteraction, "UI" }, +    { v3Scope, "S" }, +    { v3Confidentiality, "C" }, +    { v3Integrity, "I" }, +    { v3Availability, "A" }, +    { v3ExploitCodeMaturity, "E" }, +    { v3RemediationLevel, "RL" }, +    { v3ReportConfidence, "RC" }, +    { v3ConfidentialityRequirement, "CR" }, +    { v3IntegrityRequirement, "IR" }, +    { v3AvailabilityRequirement, "AR" }, +    { v3ModifiedAttackVector, "MAV" }, +    { v3ModifiedAttackComplexity, "MAC" }, +    { v3ModifiedPrivilegesRequired, "MPR" }, +    { v3ModifiedUserInteraction, "MUI" }, +    { v3ModifiedScope, "MS" }, +    { v3ModifiedConfidentiality, "MC" }, +    { v3ModifiedIntegrity, "MI" }, +    { v3ModifiedAvailability, "MA" }, + +    { v3Key(255), "v3Key(255)" }, +  } + +  for _, test := range(tests) { +    t.Run(test.exp, func(t *testing.T) { +      got := test.val.String() +      if got != test.exp { +        t.Errorf("got \"%s\", exp \"%s\"", got, test.exp) +      } +    }) +  } +} + +func TestV3KeyName(t *testing.T) { +  tests := []struct { +    val v3Key +    exp string +  } { +    { v3AttackVector, "Attack Vector" }, +    { v3AttackComplexity, "Attack Complexity" }, +    { v3PrivilegesRequired, "Privileges Required" }, +    { v3UserInteraction, "User Interaction" }, +    { v3Scope, "Scope" }, +    { v3Confidentiality, "Confidentiality" }, +    { v3Integrity, "Integrity" }, +    { v3Availability, "Availability" }, +    { v3ExploitCodeMaturity, "Exploit Code Maturity" }, +    { v3RemediationLevel, "Remediation Level" }, +    { v3ReportConfidence, "Report Confidence" }, +    { v3ConfidentialityRequirement, "Confidentiality Requirement" }, +    { v3IntegrityRequirement, "Integrity Requirement" }, +    { v3AvailabilityRequirement, "Availability Requirement" }, +    { v3ModifiedAttackVector, "Modified Attack Vector" }, +    { v3ModifiedAttackComplexity, "Modified Attack Complexity" }, +    { v3ModifiedPrivilegesRequired, "Modified Privileges Required" }, +    { v3ModifiedUserInteraction, "Modified User Interaction" }, +    { v3ModifiedScope, "Modified Scope" }, +    { v3ModifiedConfidentiality, "Modified Confidentiality" }, +    { v3ModifiedIntegrity, "Modified Integrity" }, +    { v3ModifiedAvailability, "Modified Availability" }, +  } + +  for _, test := range(tests) { +    t.Run(test.exp, func(t *testing.T) { +      got := test.val.Name() +      if got != test.exp { +        t.Errorf("got \"%s\", exp \"%s\"", got, test.exp) +      } +    }) +  } +} + +func TestV3KeyCategory(t *testing.T) { +  tests := []struct { +    val v3Key +    exp Category +  } { +    { v3AttackVector, Base }, +    { v3AttackComplexity, Base }, +    { v3PrivilegesRequired, Base }, +    { v3UserInteraction, Base }, +    { v3Scope, Base }, +    { v3Confidentiality, Base }, +    { v3Integrity, Base }, +    { v3Availability, Base }, +    { v3ExploitCodeMaturity, Temporal }, +    { v3RemediationLevel, Temporal }, +    { v3ReportConfidence, Temporal }, +    { v3ConfidentialityRequirement, Environmental }, +    { v3IntegrityRequirement, Environmental }, +    { v3AvailabilityRequirement, Environmental }, +    { v3ModifiedAttackVector, Environmental }, +    { v3ModifiedAttackComplexity, Environmental }, +    { v3ModifiedPrivilegesRequired, Environmental }, +    { v3ModifiedUserInteraction, Environmental }, +    { v3ModifiedScope, Environmental }, +    { v3ModifiedConfidentiality, Environmental }, +    { v3ModifiedIntegrity, Environmental }, +    { v3ModifiedAvailability, Environmental }, +  } + +  for _, test := range(tests) { +    t.Run(test.val.String(), func(t *testing.T) { +      got := test.val.Category() +      if got != test.exp { +        t.Errorf("got \"%s\", exp \"%s\"", got, test.exp) +      } +    }) +  } +} | 
