From 9d8a8af6ae35f5060f8e5970323d733961619a6d Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Sat, 25 Jan 2025 23:25:31 +0100 Subject: [PATCH 1/6] refactor: simplify creation of new rules --- internal/engine.go | 71 +--- internal/lints/default_golangci.go | 2 +- internal/lints/gno_analyzer.go | 2 +- internal/lints/regex_lint_test.go | 2 +- internal/lints/repeated_regex_compilation.go | 2 +- internal/rule_set.go | 364 +++---------------- 6 files changed, 60 insertions(+), 383 deletions(-) diff --git a/internal/engine.go b/internal/engine.go index c103ff0..cfe5346 100644 --- a/internal/engine.go +++ b/internal/engine.go @@ -30,41 +30,19 @@ func NewEngine(rootDir string, source []byte, rules map[string]tt.ConfigRule) (* return engine, nil } -// Define the ruleConstructor type -type ruleConstructor func() LintRule - -// Define the ruleMap type -type ruleMap map[string]ruleConstructor - -// Create a map to hold the mappings of rule names to their constructors -var allRuleConstructors = ruleMap{ - "golangci-lint": NewGolangciLintRule, - "early-return-opportunity": NewEarlyReturnOpportunityRule, - "simplify-slice-range": NewSimplifySliceExprRule, - "unnecessary-type-conversion": NewUnnecessaryConversionRule, - "emit-format": NewEmitFormatRule, - "cycle-detection": NewDetectCycleRule, - "unused-package": NewGnoSpecificRule, - "repeated-regex-compilation": NewRepeatedRegexCompilationRule, - "useless-break": NewUselessBreakRule, - "defer-issues": NewDeferRule, - "const-error-declaration": NewConstErrorDeclarationRule, -} - func (e *Engine) applyRules(rules map[string]tt.ConfigRule) { e.rules = make(map[string]LintRule) e.registerDefaultRules() // Iterate over the rules and apply severity for key, rule := range rules { - r := e.findRule(key) - if r == nil { - newRuleCstr := allRuleConstructors[key] - if newRuleCstr == nil { - // Unknown rule, continue to the next one - continue - } - newRule := newRuleCstr() + r, ok := e.findRule(key) + if !ok { + newRule, exists := allRules[key] + if !exists { + // Unknown rule, continue to the next one + continue + } newRule.SetSeverity(rule.Severity) e.rules[key] = newRule } else { @@ -77,28 +55,22 @@ func (e *Engine) applyRules(rules map[string]tt.ConfigRule) { } func (e *Engine) registerDefaultRules() { - // iterate over allRuleConstructors and add them to the rules map if severity is not off - for key, newRuleCstr := range allRuleConstructors { - newRule := newRuleCstr() + // iterate over allRules and add them to the rules map if severity is not off + for key, newRule := range allRules { if newRule.Severity() != tt.SeverityOff { + newRule.SetName(key) e.rules[key] = newRule } } } -func (e *Engine) findRule(name string) LintRule { - if rule, ok := e.rules[name]; ok { - return rule - } - return nil +func (e *Engine) findRule(name string) (LintRule, bool) { + rule, exists := e.rules[name] + return rule, exists } // Run applies all lint rules to the given file and returns a slice of Issues. func (e *Engine) Run(filename string) ([]tt.Issue, error) { - if strings.HasSuffix(filename, ".mod") { - return e.runModCheck(filename) - } - tempFile, err := e.prepareFile(filename) if err != nil { return nil, err @@ -204,23 +176,6 @@ func (e *Engine) prepareFile(filename string) (string, error) { return filename, nil } -func (e *Engine) runModCheck(filename string) ([]tt.Issue, error) { - var allIssues []tt.Issue - for _, rule := range e.rules { - if e.ignoredRules[rule.Name()] { - continue - } - if modRule, ok := rule.(ModRule); ok { - issues, err := modRule.CheckMod(filename) - if err != nil { - return nil, fmt.Errorf("error checking .mod file: %w", err) - } - allIssues = append(allIssues, issues...) - } - } - return allIssues, nil -} - func (e *Engine) cleanupTemp(temp string) { if temp != "" && strings.HasPrefix(filepath.Base(temp), "temp_") { _ = os.Remove(temp) diff --git a/internal/lints/default_golangci.go b/internal/lints/default_golangci.go index ca3a979..e0193fe 100644 --- a/internal/lints/default_golangci.go +++ b/internal/lints/default_golangci.go @@ -39,7 +39,7 @@ type golangciOutput struct { } `json:"Issues"` } -func RunGolangciLint(filename string, severity tt.Severity) ([]tt.Issue, error) { +func RunGolangciLint(filename string, _ *ast.File, _ *token.FileSet, severity tt.Severity) ([]tt.Issue, error) { cmd := exec.Command("golangci-lint", "run", "--config=./.golangci.yml", "--out-format=json", filename) output, _ := cmd.CombinedOutput() diff --git a/internal/lints/gno_analyzer.go b/internal/lints/gno_analyzer.go index 89c424b..996acb3 100644 --- a/internal/lints/gno_analyzer.go +++ b/internal/lints/gno_analyzer.go @@ -25,7 +25,7 @@ type Dependency struct { type Dependencies map[string]*Dependency -func DetectGnoPackageImports(filename string, severity tt.Severity) ([]tt.Issue, error) { +func DetectGnoPackageImports(filename string, _ *ast.File, _ *token.FileSet, severity tt.Severity) ([]tt.Issue, error) { file, deps, err := analyzeFile(filename) if err != nil { return nil, fmt.Errorf("error analyzing file: %w", err) diff --git a/internal/lints/regex_lint_test.go b/internal/lints/regex_lint_test.go index 2d7068d..c125e77 100644 --- a/internal/lints/regex_lint_test.go +++ b/internal/lints/regex_lint_test.go @@ -86,7 +86,7 @@ func multipleRepeats() { node, err := parser.ParseFile(fset, tempFile, nil, parser.ParseComments) require.NoError(t, err) - issues, err := DetectRepeatedRegexCompilation(tempFile, node, types.SeverityError) + issues, err := DetectRepeatedRegexCompilation(tempFile, node, fset, types.SeverityError) require.NoError(t, err) assert.Len(t, issues, tt.expected) diff --git a/internal/lints/repeated_regex_compilation.go b/internal/lints/repeated_regex_compilation.go index 6c84cef..6da9330 100644 --- a/internal/lints/repeated_regex_compilation.go +++ b/internal/lints/repeated_regex_compilation.go @@ -15,7 +15,7 @@ var RepeatedRegexCompilationAnalyzer = &analysis.Analyzer{ Run: runRepeatedRegexCompilation, } -func DetectRepeatedRegexCompilation(filename string, node *ast.File, severity tt.Severity) ([]tt.Issue, error) { +func DetectRepeatedRegexCompilation(filename string, node *ast.File, _ *token.FileSet, severity tt.Severity) ([]tt.Issue, error) { imports := extractImports(node, func(path string) bool { return path == "regexp" }) diff --git a/internal/rule_set.go b/internal/rule_set.go index 1e3e299..874c3c5 100644 --- a/internal/rule_set.go +++ b/internal/rule_set.go @@ -9,342 +9,64 @@ import ( ) /* -* Implement each lint rule as a separate struct +* Implement each lint rule as a a new LintRule struct. */ -// LintRule defines the interface for all lint rules. -type LintRule interface { - // Check runs the lint rule on the given file and returns a slice of Issues. - Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) - - // Name returns the name of the lint rule. - Name() string - - // Severity returns the severity of the lint rule. - Severity() tt.Severity - - // SetSeverity sets the severity of the lint rule. - SetSeverity(tt.Severity) -} - -type GolangciLintRule struct { - severity tt.Severity -} - -func NewGolangciLintRule() LintRule { - return &GolangciLintRule{ - severity: tt.SeverityWarning, - } -} - -func (r *GolangciLintRule) Check(filename string, _ *ast.File, _ *token.FileSet) ([]tt.Issue, error) { - return lints.RunGolangciLint(filename, r.severity) -} - -func (r *GolangciLintRule) Name() string { - return "golangci-lint" -} - -func (r *GolangciLintRule) Severity() tt.Severity { - return r.severity -} - -func (r *GolangciLintRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type SimplifySliceExprRule struct { - severity tt.Severity -} - -func NewSimplifySliceExprRule() LintRule { - return &SimplifySliceExprRule{ - severity: tt.SeverityError, - } -} - -func (r *SimplifySliceExprRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectUnnecessarySliceLength(filename, node, fset, r.severity) -} - -func (r *SimplifySliceExprRule) Name() string { - return "simplify-slice-range" -} - -func (r *SimplifySliceExprRule) Severity() tt.Severity { - return r.severity -} - -func (r *SimplifySliceExprRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type UnnecessaryConversionRule struct { - severity tt.Severity -} - -func NewUnnecessaryConversionRule() LintRule { - return &UnnecessaryConversionRule{ - severity: tt.SeverityWarning, - } -} - -func (r *UnnecessaryConversionRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectUnnecessaryConversions(filename, node, fset, r.severity) -} - -func (r *UnnecessaryConversionRule) Name() string { - return "unnecessary-type-conversion" -} - -func (r *UnnecessaryConversionRule) Severity() tt.Severity { - return r.severity -} - -func (r *UnnecessaryConversionRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type DetectCycleRule struct { - severity tt.Severity -} - -func NewDetectCycleRule() LintRule { - return &DetectCycleRule{ - severity: tt.SeverityError, // TODO - } -} - -func (r *DetectCycleRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectCycle(filename, node, fset, r.severity) -} - -func (r *DetectCycleRule) Name() string { - return "cycle-detection" -} - -func (r *DetectCycleRule) Severity() tt.Severity { - return r.severity -} - -func (r *DetectCycleRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type EmitFormatRule struct { - severity tt.Severity -} - -func NewEmitFormatRule() LintRule { - return &EmitFormatRule{ - severity: tt.SeverityInfo, - } -} - -func (r *EmitFormatRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectEmitFormat(filename, node, fset, r.severity) -} - -func (r *EmitFormatRule) Name() string { - return "emit-format" -} - -func (r *EmitFormatRule) Severity() tt.Severity { - return r.severity -} - -func (r *EmitFormatRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type UselessBreakRule struct { - severity tt.Severity -} - -func NewUselessBreakRule() LintRule { - return &UselessBreakRule{ - severity: tt.SeverityError, - } -} - -func (r *UselessBreakRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectUselessBreak(filename, node, fset, r.severity) -} - -func (r *UselessBreakRule) Name() string { - return "useless-break" -} - -func (r *UselessBreakRule) Severity() tt.Severity { - return r.severity -} - -func (r *UselessBreakRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type EarlyReturnOpportunityRule struct { - severity tt.Severity -} - -func NewEarlyReturnOpportunityRule() LintRule { - return &EarlyReturnOpportunityRule{ - severity: tt.SeverityInfo, - } -} - -func (r *EarlyReturnOpportunityRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectEarlyReturnOpportunities(filename, node, fset, r.severity) -} - -func (r *EarlyReturnOpportunityRule) Name() string { - return "early-return-opportunity" -} - -func (r *EarlyReturnOpportunityRule) Severity() tt.Severity { - return r.severity -} - -func (r *EarlyReturnOpportunityRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type DeferRule struct { - severity tt.Severity -} - -func NewDeferRule() LintRule { - return &DeferRule{ - severity: tt.SeverityWarning, - } -} - -func (r *DeferRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectDeferIssues(filename, node, fset, r.severity) -} - -func (r *DeferRule) Name() string { - return "defer-issues" -} - -func (r *DeferRule) Severity() tt.Severity { - return r.severity -} - -func (r *DeferRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -type ConstErrorDeclarationRule struct { - severity tt.Severity -} - -func NewConstErrorDeclarationRule() LintRule { - return &ConstErrorDeclarationRule{ - severity: tt.SeverityError, - } -} - -func (r *ConstErrorDeclarationRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectConstErrorDeclaration(filename, node, fset, r.severity) -} - -func (r *ConstErrorDeclarationRule) Name() string { - return "const-error-declaration" -} - -func (r *ConstErrorDeclarationRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -func (r *ConstErrorDeclarationRule) Severity() tt.Severity { - return r.severity -} - -// ----------------------------------------------------------------------------- -// Regex related rules - -type RepeatedRegexCompilationRule struct { - severity tt.Severity -} - -func NewRepeatedRegexCompilationRule() LintRule { - return &RepeatedRegexCompilationRule{ - severity: tt.SeverityWarning, - } -} - -func (r *RepeatedRegexCompilationRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectRepeatedRegexCompilation(filename, node, r.severity) -} - -func (r *RepeatedRegexCompilationRule) Name() string { - return "repeated-regex-compilation" -} - -func (r *RepeatedRegexCompilationRule) Severity() tt.Severity { - return r.severity +// LintRule defines the struct for all lint rules. +type LintRule struct { + severity tt.Severity + check func(filename string, node *ast.File, fset *token.FileSet, severity tt.Severity) ([]tt.Issue, error) + name string } -func (r *RepeatedRegexCompilationRule) SetSeverity(severity tt.Severity) { +func (r LintRule) SetSeverity(severity tt.Severity) { r.severity = severity } -// ----------------------------------------------------------------------------- - -type CyclomaticComplexityRule struct { - Threshold int - severity tt.Severity -} - -func NewCyclomaticComplexityRule(threshold int) LintRule { - return &CyclomaticComplexityRule{ - Threshold: threshold, - severity: tt.SeverityError, - } -} - -func (r *CyclomaticComplexityRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { - return lints.DetectHighCyclomaticComplexity(filename, r.Threshold, r.severity) -} - -func (r *CyclomaticComplexityRule) Name() string { - return "high-cyclomatic-complexity" -} - -func (r *CyclomaticComplexityRule) Severity() tt.Severity { +func (r LintRule) Severity() tt.Severity { return r.severity } -func (r *CyclomaticComplexityRule) SetSeverity(severity tt.Severity) { - r.severity = severity -} - -// ----------------------------------------------------------------------------- - -// GnoSpecificRule checks for gno-specific package imports. (p, r and std) -type GnoSpecificRule struct { - severity tt.Severity -} - -func NewGnoSpecificRule() LintRule { - return &GnoSpecificRule{ - severity: tt.SeverityWarning, - } +func (r LintRule) SetName(name string) { + r.name = name } -func (r *GnoSpecificRule) Check(filename string, _ *ast.File, _ *token.FileSet) ([]tt.Issue, error) { - return lints.DetectGnoPackageImports(filename, r.severity) +func (r LintRule) Name() string { + return r.name } -func (r *GnoSpecificRule) Name() string { - return "unused-package" +func (r LintRule) Check(filename string, node *ast.File, fset *token.FileSet) ([]tt.Issue, error) { + return r.check(filename, node, fset, r.severity) } -func (r *GnoSpecificRule) Severity() tt.Severity { - return r.severity -} +var ( + GolangciLintRule = LintRule{severity: tt.SeverityWarning, check: lints.RunGolangciLint} + SimplifySliceExprRule = LintRule{severity: tt.SeverityError, check: lints.DetectUnnecessarySliceLength} + UnnecessaryConversionRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectUnnecessaryConversions} + DetectCycleRule = LintRule{severity: tt.SeverityError, check: lints.DetectCycle} + EmitFormatRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEmitFormat} + UselessBreakRule = LintRule{severity: tt.SeverityError, check: lints.DetectUselessBreak} + EarlyReturnOpportunityRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEarlyReturnOpportunities} + DeferRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectDeferIssues} + ConstErrorDeclarationRule = LintRule{severity: tt.SeverityError, check: lints.DetectConstErrorDeclaration} + RepeatedRegexCompilationRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectRepeatedRegexCompilation} + GnoSpecificRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectGnoPackageImports} +) -func (r *GnoSpecificRule) SetSeverity(severity tt.Severity) { - r.severity = severity +// Define the ruleMap type +type ruleMap map[string]LintRule + +// Create a map to hold the mappings of rule names to LintRule structs +var allRules = ruleMap{ + "golangci-lint": GolangciLintRule, + "simplify-slice-range": SimplifySliceExprRule, + "unnecessary-type-conversion": UnnecessaryConversionRule, + "cycle-detection": DetectCycleRule, + "emit-format": EmitFormatRule, + "useless-break": UselessBreakRule, + "early-return-opportunity": EarlyReturnOpportunityRule, + "defer-issues": DeferRule, + "const-error-declaration": ConstErrorDeclarationRule, + "repeated-regex-compilation": RepeatedRegexCompilationRule, + "unused-package": GnoSpecificRule, } From 55174b1e0b31249a9daf2dd032cee60c7e8ada09 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Sat, 25 Jan 2025 23:34:49 +0100 Subject: [PATCH 2/6] doc: update documentation to create a new rule --- README.md | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 85a20bf..8718063 100644 --- a/README.md +++ b/README.md @@ -108,37 +108,23 @@ Our linter allows addition of custom lint rules beyond the default golangci-lint 4. Once the RFC is approved, proceed with the implementation: - a. Implement the `LintRule` interface for your new rule: + a. Create a new variable of type `LintRule` for your new rule: ```go - type NewRule struct{} + NewRule = LintRule{severity: tt.SeverityWarning, check: lints.RunNewRule} - func (r *NewRule) Check(filename string, node *ast.File) ([]types.Issue, error) { + func RunNewRule(filename string, node *ast.File, fset *token.FileSet, severity tt.Severity) ([]types.Issue, error) { // Implement your lint rule logic here // return a slice of Issues and any error encountered } ``` - b. Register your new rule in the `registerAllRules` and maybe `registerDefaultRules` method of the `Engine` struct in `internal/engine.go`: + b. Add your rule to `allRules` mapping: ```go - func (e *Engine) registerDefaultRules() { - e.rules = append(e.rules, - &GolangciLintRule{}, - // ... - &NewRule{}, // Add your new rule here - ) - } - ``` - - ```go - func (e *Engine) registerAllRules() { - e.rules = append(e.rules, - &GolangciLintRule{}, - // ... - &NewRule{}, // Add your new rule here - ) - } + var allRules = ruleMap{ + "new-rule": NewRule, + } ``` 5. (Optional) If your rule requires special formatting, create a new formatter in the `formatter` package: From 0ebaf428b5ef22e7bfbeb8096573a1e8fb12ab43 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Sat, 25 Jan 2025 23:40:19 +0100 Subject: [PATCH 3/6] style: format files --- internal/engine.go | 6 +++--- internal/rule_set.go | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/engine.go b/internal/engine.go index cfe5346..47f26d0 100644 --- a/internal/engine.go +++ b/internal/engine.go @@ -40,9 +40,9 @@ func (e *Engine) applyRules(rules map[string]tt.ConfigRule) { if !ok { newRule, exists := allRules[key] if !exists { - // Unknown rule, continue to the next one - continue - } + // Unknown rule, continue to the next one + continue + } newRule.SetSeverity(rule.Severity) e.rules[key] = newRule } else { diff --git a/internal/rule_set.go b/internal/rule_set.go index 874c3c5..dde62e7 100644 --- a/internal/rule_set.go +++ b/internal/rule_set.go @@ -14,9 +14,9 @@ import ( // LintRule defines the struct for all lint rules. type LintRule struct { - severity tt.Severity - check func(filename string, node *ast.File, fset *token.FileSet, severity tt.Severity) ([]tt.Issue, error) - name string + severity tt.Severity + check func(filename string, node *ast.File, fset *token.FileSet, severity tt.Severity) ([]tt.Issue, error) + name string } func (r LintRule) SetSeverity(severity tt.Severity) { @@ -40,17 +40,17 @@ func (r LintRule) Check(filename string, node *ast.File, fset *token.FileSet) ([ } var ( - GolangciLintRule = LintRule{severity: tt.SeverityWarning, check: lints.RunGolangciLint} - SimplifySliceExprRule = LintRule{severity: tt.SeverityError, check: lints.DetectUnnecessarySliceLength} - UnnecessaryConversionRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectUnnecessaryConversions} - DetectCycleRule = LintRule{severity: tt.SeverityError, check: lints.DetectCycle} - EmitFormatRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEmitFormat} - UselessBreakRule = LintRule{severity: tt.SeverityError, check: lints.DetectUselessBreak} - EarlyReturnOpportunityRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEarlyReturnOpportunities} - DeferRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectDeferIssues} - ConstErrorDeclarationRule = LintRule{severity: tt.SeverityError, check: lints.DetectConstErrorDeclaration} + GolangciLintRule = LintRule{severity: tt.SeverityWarning, check: lints.RunGolangciLint} + SimplifySliceExprRule = LintRule{severity: tt.SeverityError, check: lints.DetectUnnecessarySliceLength} + UnnecessaryConversionRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectUnnecessaryConversions} + DetectCycleRule = LintRule{severity: tt.SeverityError, check: lints.DetectCycle} + EmitFormatRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEmitFormat} + UselessBreakRule = LintRule{severity: tt.SeverityError, check: lints.DetectUselessBreak} + EarlyReturnOpportunityRule = LintRule{severity: tt.SeverityInfo, check: lints.DetectEarlyReturnOpportunities} + DeferRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectDeferIssues} + ConstErrorDeclarationRule = LintRule{severity: tt.SeverityError, check: lints.DetectConstErrorDeclaration} RepeatedRegexCompilationRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectRepeatedRegexCompilation} - GnoSpecificRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectGnoPackageImports} + GnoSpecificRule = LintRule{severity: tt.SeverityWarning, check: lints.DetectGnoPackageImports} ) // Define the ruleMap type From 1c0334f6f51694bafaf1d2ce5f5bf61957fe1577 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Mon, 27 Jan 2025 01:11:04 +0100 Subject: [PATCH 4/6] feat: mutex inside captureOutput --- cmd/tlin/main_test.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/cmd/tlin/main_test.go b/cmd/tlin/main_test.go index 02d0915..b5f8d82 100644 --- a/cmd/tlin/main_test.go +++ b/cmd/tlin/main_test.go @@ -381,17 +381,22 @@ func createTempFileWithContent(t *testing.T, content string) string { return tempFile.Name() } +var mu sync.Mutex + func captureOutput(t *testing.T, f func()) string { - t.Helper() - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w + t.Helper() + mu.Lock() + defer mu.Unlock() + + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w - f() + f() - w.Close() - os.Stdout = oldStdout - var buf bytes.Buffer - io.Copy(&buf, r) - return buf.String() + w.Close() + os.Stdout = oldStdout + var buf bytes.Buffer + io.Copy(&buf, r) + return buf.String() } From e4bd666d71cfc7381a67fd042fc5940c19e20a22 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Mon, 27 Jan 2025 01:12:39 +0100 Subject: [PATCH 5/6] feat: add sync as dependency --- cmd/tlin/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/tlin/main_test.go b/cmd/tlin/main_test.go index b5f8d82..cf4c8d1 100644 --- a/cmd/tlin/main_test.go +++ b/cmd/tlin/main_test.go @@ -13,6 +13,7 @@ import ( "strings" "testing" "time" + "sync" tt "github.com/gnolang/tlin/internal/types" "github.com/gnolang/tlin/lint" From 28fa7ac509bc03ed663dafad3b6785c145f227f8 Mon Sep 17 00:00:00 2001 From: 0xtekgrinder <0xtekgrinder@protonmail.com> Date: Mon, 27 Jan 2025 01:14:19 +0100 Subject: [PATCH 6/6] style: format main_test --- cmd/tlin/main_test.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cmd/tlin/main_test.go b/cmd/tlin/main_test.go index cf4c8d1..f1656ef 100644 --- a/cmd/tlin/main_test.go +++ b/cmd/tlin/main_test.go @@ -11,9 +11,9 @@ import ( "os/exec" "path/filepath" "strings" + "sync" "testing" "time" - "sync" tt "github.com/gnolang/tlin/internal/types" "github.com/gnolang/tlin/lint" @@ -385,19 +385,19 @@ func createTempFileWithContent(t *testing.T, content string) string { var mu sync.Mutex func captureOutput(t *testing.T, f func()) string { - t.Helper() - mu.Lock() - defer mu.Unlock() + t.Helper() + mu.Lock() + defer mu.Unlock() - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w - f() + f() - w.Close() - os.Stdout = oldStdout - var buf bytes.Buffer - io.Copy(&buf, r) - return buf.String() + w.Close() + os.Stdout = oldStdout + var buf bytes.Buffer + io.Copy(&buf, r) + return buf.String() }