Beispiel #1
0
// Testing rule: NEVER_ALLOCATED_MAP_WITH_NEW
// Allocating maps with new returns a nil pointer, therefor one should use make.
func TestDetectionOfAllocatingMapWithNew(t *testing.T) {
	expectedViolations, _ := linter.DetectViolations("./testcode/newmap")
	actualViolations := []actualViolation{
		{SrcLine: 11, Type: linter.MAP_ALLOCATED_WITH_NEW},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}

}
Beispiel #2
0
// GitHub Issue #4 list a scenario where the tool detects a false positive of rule ERROR_IGNORED.
// This test verifies correction of the behaviour.
func TestDetectionOfErrorIgnoredInReturn(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/errorinreturn")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{}

	if len(expectedViolations) > 0 {
		// Only verify violations if there is more than one file containing violations!
		if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
			t.Fatal(err)
		}
	}
}
Beispiel #3
0
// Testing rule: EMPTY_IF_BODY
// Empty if-bodies are unnecessary and ineffective.
func TestDetectionOfEmptyIfBody(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/emptyifbody")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 11, Type: linter.EMPTY_IF_BODY},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #4
0
// Testing rule: RACE_CONDITION
// Races will occur, since multiple Go-routines will share the same counter variable.
func TestDetectionOfRacesInLoopClosures(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/threadlooping")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 18, Type: linter.RACE_CONDITION},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #5
0
func TestDetectionOfHighCyclomatiComplexity(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/cyclomaticomplexity")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 13, Type: linter.CYCLOMATIC_COMPLEXITY},
	}

	if len(expectedViolations) > 0 {
		// Only verify violations if there is more than one file containing violations!
		if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
			t.Fatal(err)
		}
	}
}
Beispiel #6
0
// Testing rule: GOTO_USED
// Jumping around in the code using GOTO (including BREAK, CONTINUE, GOTO, FALLTHROUGH)
// is considered confusing and harmful.
func TestDetectionOfLabeledBranching(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/labeledbranch")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 15, Type: linter.GOTO_USED},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #7
0
// Testing rule: RETURN_KILLS_CODE
// One should never return unconditionally, except from the last statement in a func or method.
func TestDetectionOfEarlyReturn(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/earlyreturn")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 13, Type: linter.RETURN_KILLS_CODE},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #8
0
// Printing from fmt package is not thread safe and should be avoided in production and detected!
// Testing rule: FMT_PRINTING
func TestDetectionOfPrintingFromFmtPackage(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/fmtprinting")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 11, Type: linter.FMT_PRINTING},
		{SrcLine: 12, Type: linter.FMT_PRINTING},
		{SrcLine: 13, Type: linter.FMT_PRINTING},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #9
0
// Testing rule: ERROR_IGNORED
// Errors should never be ignored, might lead to program crashes.
func TestDetectionOfIgnoredErrors(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/errorignored")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 16, Type: linter.ERROR_IGNORED},
		{SrcLine: 17, Type: linter.ERROR_IGNORED},
		{SrcLine: 22, Type: linter.ERROR_IGNORED},
		{SrcLine: 27, Type: linter.ERROR_IGNORED},
		{SrcLine: 35, Type: linter.ERROR_IGNORED},
		{SrcLine: 51, Type: linter.ERROR_IGNORED},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #10
0
// Testing rule: CONDITION_EVALUATED_STATICALLY
// Condition that can be evaluated statically are wasted and performance-reducing.
func TestDetectionOfConditionEvaluatedStatically(t *testing.T) {
	expectedViolations, err := linter.DetectViolations("./testcode/staticconditions")
	if err != nil {
		t.Fatal(err)
	}

	actualViolations := []actualViolation{
		{SrcLine: 14, Type: linter.CONDITION_EVALUATED_STATICALLY},
		{SrcLine: 18, Type: linter.CONDITION_EVALUATED_STATICALLY},
		{SrcLine: 22, Type: linter.CONDITION_EVALUATED_STATICALLY},
		{SrcLine: 26, Type: linter.CONDITION_EVALUATED_STATICALLY},
		//{SrcLine: 32, Type: linter.CONDITION_EVALUATED_STATICALLY}, TODO: Possible to statically trace a variable value?
		{SrcLine: 38, Type: linter.CONDITION_EVALUATED_STATICALLY},
		{SrcLine: 41, Type: linter.CONDITION_EVALUATED_STATICALLY},
	}

	if len(expectedViolations) <= 0 {
		t.Fatal("There is no functions containing violations.")
	}
	if err := verifyViolations(expectedViolations[0].Violations[0].Violations, actualViolations); err != nil {
		t.Fatal(err)
	}
}
Beispiel #11
0
func main() {
	flag.Parse()

	if flag.NFlag() < 1 {
		flag.Usage()
	}

	// Option dir selected.
	if len(*sourceRootDir) > 0 {
		start := time.Now()

		goPackageViolations, err := linter.DetectViolations(*sourceRootDir) // Start the analysis.
		if err != nil {
			log.Fatal(err)
		}
		timeUsed := time.Since(start)

		// Direct output to console as JSON.
		if *jsonOutput && len(goPackageViolations) > 0 {

			// Aggregate GoFiles to JSON marshalling.
			violationsMap := make(map[string]*linter.GoFile)
			for _, goPackage := range goPackageViolations {
				for _, goFile := range goPackage.Violations {
					if gf, ok := violationsMap[goFile.FilePath]; ok {
						gf.Violations = append(gf.Violations, goFile.Violations...)
					} else {
						violationsMap[goFile.FilePath] = goFile
					}
				}
			}

			// Convert to list for JSON marshalling.
			var violations []*linter.GoFile
			for _, value := range violationsMap {
				violations = append(violations, value)
			}

			json, err := json.MarshalIndent(violations, "", "\t")
			if err != nil {
				log.Fatal(err)
			}
			if _, err := os.Stdout.Write(json); err != nil {
				panic(err)
			}

		} else {
			log.SetOutput(os.Stdout) // We want to send output to stdout, instead of Stderr.
			numberOfViolations := 0
			linesOfCode := 0
			linesOfComments := 0

			// Nicely print the output to the console.
			log.Println("-----------------------------------------------------------------------------------------------")
			for _, goPackage := range goPackageViolations {
				log.Printf("PACKAGE: %s (%s)", goPackage.Pack.Name, goPackage.Path)

				for _, goFile := range goPackage.Violations {
					log.Printf("\tViolations in %s :", filepath.Base(goFile.FilePath))
					for i, vio := range goFile.Violations {
						log.Printf("\t\t%d) %s\n", i, vio)
					}
					linesOfCode += goFile.LinesOfCode
					linesOfComments += goFile.LinesOfComments
				}

				numberOfViolations += len(goPackage.Violations)
				log.Println("-----------------------------------------------------------------------------------------------")
			}
			log.Println("## ANALYSIS SUMMARY ##")
			log.Printf("Total %d violations found!\n", numberOfViolations)
			log.Printf("Total number of Go files: %d\n", countGoFiles(*sourceRootDir))
			log.Printf("Total lines of code (LOC): %d\n", linesOfCode)
			log.Printf("Total lines of comments: %d\n", linesOfComments)
			log.Printf("Total time used: %s\n", timeUsed)
			log.Printf("For rule details: %s\n", globalvars.WIKI_PAGE)
		}

	}

	// Print help.
	if *printHelp {
		flag.Usage()
	}
}