2019-12-14 09:27:06 +02:00
// Test of cognitive complexity.
// Package pkg ...
package pkg
import (
"fmt"
ast "go/ast"
"log"
2019-12-14 17:19:08 +02:00
"testing"
"github.com/blang/semver"
"k8s.io/klog"
2019-12-14 09:27:06 +02:00
)
2019-12-14 10:01:22 +02:00
// Test IF and Boolean expr
2019-12-14 09:27:06 +02:00
func f ( x int ) bool { // MATCH /function f has cognitive complexity 3 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
if x > 0 && true || false { // +3
2019-12-14 09:27:06 +02:00
return true
} else {
log . Printf ( "non-positive x: %d" , x )
}
return false
}
2019-12-14 10:01:22 +02:00
// Test IF
2019-12-14 09:27:06 +02:00
func g ( f func ( ) bool ) string { // MATCH /function g has cognitive complexity 1 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
if ok := f ( ) ; ok { // +1
2019-12-14 09:27:06 +02:00
return "it's okay"
} else {
return "it's NOT okay!"
}
}
2019-12-14 10:01:22 +02:00
// Test Boolean expr
2019-12-14 09:27:06 +02:00
func h ( a , b , c , d , e , f bool ) bool { // MATCH /function h has cognitive complexity 2 (> max enabled 0)/
2019-12-14 17:19:08 +02:00
return a && b && c || d || e && f //FIXME: complexity should be 3?
2019-12-14 09:27:06 +02:00
}
func i ( a , b , c , d , e , f bool ) bool { // MATCH /function i has cognitive complexity 2 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
result := a && b && c || d || e // +2
2019-12-14 09:27:06 +02:00
return result
}
func j ( a , b , c , d , e , f bool ) bool { // MATCH /function j has cognitive complexity 2 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
result := z ( a && ! ( b && c ) ) // +2
2019-12-14 09:27:06 +02:00
return result
}
2019-12-14 10:01:22 +02:00
// Test Switch expr
2019-12-14 09:27:06 +02:00
func k ( a , b , c , d , e , f bool ) bool { // MATCH /function k has cognitive complexity 1 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
switch expr { // +1
2019-12-14 09:27:06 +02:00
case cond1 :
case cond2 :
default :
}
return result
}
2019-12-14 10:01:22 +02:00
// Test nesting FOR expr + nested IF
2019-12-14 09:27:06 +02:00
func l ( ) { // MATCH /function l has cognitive complexity 6 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
for i := 1 ; i <= max ; i ++ { // +1
for j := 2 ; j < i ; j ++ { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
2019-12-14 09:27:06 +02:00
continue
}
}
total += i
}
return total
}
2019-12-14 10:01:22 +02:00
// Test nesting IF
2019-12-14 09:27:06 +02:00
func m ( ) { // MATCH /function m has cognitive complexity 6 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
if i <= max { // +1
if j < i { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
2019-12-14 09:27:06 +02:00
return 0
}
}
total += i
}
return total
}
2019-12-14 10:01:22 +02:00
// Test nesting IF + nested FOR
2019-12-14 09:27:06 +02:00
func n ( ) { // MATCH /function n has cognitive complexity 6 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
if i > max { // +1
for j := 2 ; j < i ; j ++ { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
2019-12-14 09:27:06 +02:00
continue
}
}
total += i
}
return total
}
2019-12-14 10:01:22 +02:00
// Test nesting
2019-12-14 09:27:06 +02:00
func o ( ) { // MATCH /function o has cognitive complexity 12 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
if i > max { // +1
if j < i { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
2019-12-14 09:27:06 +02:00
return
}
}
total += i
}
2019-12-14 10:01:22 +02:00
if i > max { // +1
if j < i { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
2019-12-14 09:27:06 +02:00
return
}
}
total += i
}
}
2019-12-14 10:01:22 +02:00
// Tests TYPE SWITCH
2019-12-14 09:27:06 +02:00
func p ( ) { // MATCH /function p has cognitive complexity 1 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
switch n := n . ( type ) { // +1
2019-12-14 09:27:06 +02:00
case * ast . IfStmt :
targets := [ ] ast . Node { n . Cond , n . Body , n . Else }
v . walk ( targets ... )
return nil
case * ast . ForStmt :
v . walk ( n . Body )
return nil
case * ast . TypeSwitchStmt :
v . walk ( n . Body )
return nil
case * ast . BinaryExpr :
v . complexity += v . binExpComplexity ( n )
2019-12-14 10:01:22 +02:00
return nil
2019-12-14 09:27:06 +02:00
}
}
2019-12-14 10:01:22 +02:00
// Test RANGE
2019-12-14 09:27:06 +02:00
func q ( ) { // MATCH /function q has cognitive complexity 1 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
for _ , t := range targets { // +1
2019-12-14 09:27:06 +02:00
ast . Walk ( v , t )
}
}
2019-12-14 10:01:22 +02:00
// Tests SELECT
2019-12-14 09:27:06 +02:00
func r ( ) { // MATCH /function r has cognitive complexity 1 (> max enabled 0)/
2019-12-14 10:01:22 +02:00
select { // +1
2019-12-14 09:27:06 +02:00
case c <- x :
x , y = y , x + y
case <- quit :
fmt . Println ( "quit" )
return
}
}
2019-12-14 10:01:22 +02:00
// Test jump to label
2019-12-14 09:27:06 +02:00
func s ( ) { // MATCH /function s has cognitive complexity 3 (> max enabled 0)/
FirstLoop :
2019-12-14 10:01:22 +02:00
for i := 0 ; i < 10 ; i ++ { // +1
2019-12-14 09:27:06 +02:00
break
}
2019-12-14 10:01:22 +02:00
for i := 0 ; i < 10 ; i ++ { // +1
break FirstLoop // +1
2019-12-14 09:27:06 +02:00
}
}
func t ( ) { // MATCH /function t has cognitive complexity 2 (> max enabled 0)/
FirstLoop :
2019-12-14 10:01:22 +02:00
for i := 0 ; i < 10 ; i ++ { // +1
goto FirstLoop // +1
2019-12-14 09:27:06 +02:00
}
}
func u ( ) { // MATCH /function u has cognitive complexity 3 (> max enabled 0)/
FirstLoop :
2019-12-14 10:01:22 +02:00
for i := 0 ; i < 10 ; i ++ { // +1
2019-12-14 09:27:06 +02:00
continue
}
2019-12-14 10:01:22 +02:00
for i := 0 ; i < 10 ; i ++ { // +1
continue FirstLoop // +1
2019-12-14 09:27:06 +02:00
}
}
2019-12-14 10:01:22 +02:00
// Tests FUNC LITERAL
2019-12-14 09:27:06 +02:00
func v ( ) { // MATCH /function v has cognitive complexity 2 (> max enabled 0)/
myFunc := func ( b bool ) {
2019-12-14 10:01:22 +02:00
if b { // +1 +1(nesting)
2019-12-14 09:27:06 +02:00
}
}
}
2019-12-14 17:19:08 +02:00
func v ( ) {
t . Run ( tc . desc , func ( t * testing . T ) { } )
}
2019-12-14 09:27:06 +02:00
func w ( ) { // MATCH /function w has cognitive complexity 3 (> max enabled 0)/
defer func ( b bool ) {
2019-12-14 10:01:22 +02:00
if b { // +1 +1(nesting)
2019-12-14 09:27:06 +02:00
}
2019-12-14 10:01:22 +02:00
} ( false || true ) // +1
2019-12-14 09:27:06 +02:00
}
2019-12-14 10:01:22 +02:00
// Test from Cognitive Complexity white paper
2019-12-14 09:27:06 +02:00
func sumOfPrimes ( max int ) int { // MATCH /function sumOfPrimes has cognitive complexity 7 (> max enabled 0)/
total := 0
OUT :
2019-12-14 10:01:22 +02:00
for i := 1 ; i <= max ; i ++ { // +1
for j := 2 ; j < i ; j ++ { // +1 +1(nesting)
if i % j == 0 { // +1 +2(nesting)
continue OUT // +1
2019-12-14 09:27:06 +02:00
}
}
total += i
}
return total
}
2019-12-14 17:19:08 +02:00
// Test from K8S
func ( m * Migrator ) MigrateIfNeeded ( target * EtcdVersionPair ) error { // MATCH /function (*Migrator).MigrateIfNeeded has cognitive complexity 18 (> max enabled 0)/
klog . Infof ( "Starting migration to %s" , target )
err := m . dataDirectory . Initialize ( target )
if err != nil { // +1
return fmt . Errorf ( "failed to initialize data directory %s: %v" , m . dataDirectory . path , err )
}
var current * EtcdVersionPair
vfExists , err := m . dataDirectory . versionFile . Exists ( )
if err != nil { // +1
return err
}
if vfExists { // +1
current , err = m . dataDirectory . versionFile . Read ( )
if err != nil { // +1 +1
return err
}
} else {
return fmt . Errorf ( "existing data directory '%s' is missing version.txt file, unable to migrate" , m . dataDirectory . path )
}
for { // +1
klog . Infof ( "Converging current version '%s' to target version '%s'" , current , target )
currentNextMinorVersion := & EtcdVersion { Version : semver . Version { Major : current . version . Major , Minor : current . version . Minor + 1 } }
switch { // +1 +1
case current . version . MajorMinorEquals ( target . version ) || currentNextMinorVersion . MajorMinorEquals ( target . version ) : // +1
klog . Infof ( "current version '%s' equals or is one minor version previous of target version '%s' - migration complete" , current , target )
err = m . dataDirectory . versionFile . Write ( target )
if err != nil { // +1 +2
return fmt . Errorf ( "failed to write version.txt to '%s': %v" , m . dataDirectory . path , err )
}
return nil
case current . storageVersion == storageEtcd2 && target . storageVersion == storageEtcd3 : // +1
return fmt . Errorf ( "upgrading from etcd2 storage to etcd3 storage is not supported" )
case current . version . Major == 3 && target . version . Major == 2 : // +1
return fmt . Errorf ( "downgrading from etcd 3.x to 2.x is not supported" )
case current . version . Major == target . version . Major && current . version . Minor < target . version . Minor : // +1
stepVersion := m . cfg . supportedVersions . NextVersionPair ( current )
klog . Infof ( "upgrading etcd from %s to %s" , current , stepVersion )
current , err = m . minorVersionUpgrade ( current , stepVersion )
case current . version . Major == 3 && target . version . Major == 3 && current . version . Minor > target . version . Minor : // +1
klog . Infof ( "rolling etcd back from %s to %s" , current , target )
current , err = m . rollbackEtcd3MinorVersion ( current , target )
}
if err != nil { // +1 +1
return err
}
}
}