Skip to content

Commit 8f4d2f7

Browse files
committed
TODO language boilerplate
1 parent cdddac4 commit 8f4d2f7

File tree

6 files changed

+194
-0
lines changed

6 files changed

+194
-0
lines changed

language/golang/language.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func (l *Language) TestFramework() (testFramework string) {
5454
return ""
5555
}
5656

57+
// HasTestsInSource returns if the tests for this language are commonly located within the corresponding implementation file.
58+
func (l *Language) HasTestsInSource() bool {
59+
return false
60+
}
61+
5762
// DefaultFileExtension returns the default file extension.
5863
func (l *Language) DefaultFileExtension() string {
5964
return ".go"

language/java/language.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ func (l *Language) TestFramework() (testFramework string) {
7070
return "JUnit 5"
7171
}
7272

73+
// HasTestsInSource returns if the tests for this language are commonly located within the corresponding implementation file.
74+
func (l *Language) HasTestsInSource() bool {
75+
return false
76+
}
77+
7378
// DefaultFileExtension returns the default file extension.
7479
func (l *Language) DefaultFileExtension() string {
7580
return ".java"

language/language.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type Language interface {
3838
TestFilePath(projectRootPath string, filePath string) (testFilePath string)
3939
// TestFramework returns the human-readable name of the test framework that should be used.
4040
TestFramework() (testFramework string)
41+
// HasTestsInSource returns if the tests for this language are commonly located within the corresponding implementation file.
42+
HasTestsInSource() bool
4143

4244
// DefaultFileExtension returns the default file extension of the implemented language.
4345
DefaultFileExtension() string

language/ruby/language.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ func (l *Language) TestFramework() (testFramework string) {
5959
return "Minitest"
6060
}
6161

62+
// HasTestsInSource returns if the tests for this language are commonly located within the corresponding implementation file.
63+
func (l *Language) HasTestsInSource() bool {
64+
return false
65+
}
66+
6267
// DefaultFileExtension returns the default file extension.
6368
func (l *Language) DefaultFileExtension() string {
6469
return ".rb"

language/rust/language.go

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package rust
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"regexp"
8+
"strconv"
9+
"strings"
10+
11+
pkgerrors "github.com/pkg/errors"
12+
13+
"github.com/symflower/eval-dev-quality/language"
14+
"github.com/symflower/eval-dev-quality/log"
15+
"github.com/symflower/eval-dev-quality/util"
16+
)
17+
18+
// Language holds a Rust language to evaluate a repository.
19+
type Language struct{}
20+
21+
func init() {
22+
language.Register(&Language{})
23+
}
24+
25+
var _ language.Language = (*Language)(nil)
26+
27+
// ID returns the unique ID of this language.
28+
func (l *Language) ID() (id string) {
29+
return "rust"
30+
}
31+
32+
// Name is the prose name of this language.
33+
func (l *Language) Name() (id string) {
34+
return "Rust"
35+
}
36+
37+
// Files returns a list of relative file paths of the repository that should be evaluated.
38+
func (l *Language) Files(logger *log.Logger, repositoryPath string) (filePaths []string, err error) {
39+
return language.Files(logger, l, repositoryPath)
40+
}
41+
42+
// ImportPath returns the import path of the given source file.
43+
func (l *Language) ImportPath(projectRootPath string, filePath string) (importPath string) {
44+
importPath = strings.ReplaceAll(filepath.Dir(filePath), string(os.PathSeparator), "::")
45+
46+
return strings.TrimPrefix(strings.TrimPrefix(importPath, "src"), "::")
47+
}
48+
49+
// TestFilePath returns the file path of a test file given the corresponding file path of the test's source file.
50+
func (l *Language) TestFilePath(projectRootPath string, filePath string) (testFilePath string) {
51+
return filePath
52+
}
53+
54+
// TestFramework returns the human-readable name of the test framework that should be used.
55+
func (l *Language) TestFramework() (testFramework string) {
56+
return ""
57+
}
58+
59+
// HasTestsInSource returns if the tests for this language are commonly located within the corresponding implementation file.
60+
func (l *Language) HasTestsInSource() bool {
61+
return true
62+
}
63+
64+
// DefaultFileExtension returns the default file extension.
65+
func (l *Language) DefaultFileExtension() string {
66+
return ".rs"
67+
}
68+
69+
// DefaultTestFileSuffix returns the default test file suffix.
70+
func (l *Language) DefaultTestFileSuffix() string {
71+
return ".rs"
72+
}
73+
74+
// ExecuteTests invokes the language specific testing on the given repository.
75+
func (l *Language) ExecuteTests(logger *log.Logger, repositoryPath string) (testResult *language.TestResult, problems []error, err error) {
76+
commandOutput, err := util.CommandWithResult(context.Background(), logger, &util.Command{
77+
Command: []string{ // TODO Move this to `symflower test` to get coverage information.
78+
"cargo",
79+
"test",
80+
},
81+
82+
Directory: repositoryPath,
83+
})
84+
if err != nil {
85+
return nil, nil, pkgerrors.WithMessage(pkgerrors.WithStack(err), commandOutput)
86+
}
87+
88+
testsTotal, testsPass, e := parseSymflowerTestOutput(commandOutput)
89+
if e != nil {
90+
problems = append(problems, pkgerrors.WithMessage(pkgerrors.WithStack(e), commandOutput))
91+
}
92+
// If there are test failures, then this is just a soft error since we still are able to receive coverage data.
93+
if err != nil {
94+
if testsTotal-testsPass <= 0 {
95+
return nil, nil, pkgerrors.WithMessage(pkgerrors.WithStack(err), commandOutput)
96+
}
97+
98+
problems = append(problems, pkgerrors.WithMessage(pkgerrors.WithStack(err), commandOutput))
99+
}
100+
101+
testResult = &language.TestResult{
102+
TestsTotal: uint(testsTotal),
103+
TestsPass: uint(testsPass),
104+
105+
StdOut: commandOutput,
106+
}
107+
108+
// coverageFilePath := "" // TODO
109+
// testResult.Coverage, err = language.CoverageObjectCountOfFile(logger, coverageFilePath)
110+
// if err != nil {
111+
// return testResult, problems, pkgerrors.WithMessage(pkgerrors.WithStack(err), commandOutput)
112+
// }
113+
114+
return testResult, problems, nil
115+
}
116+
117+
var languageRustTestSummaryRE = regexp.MustCompile(`test result: (?:ok|FAILED). (\d+) passed; (\d+) failed;`)
118+
119+
func parseSymflowerTestOutput(data string) (testsTotal int, testsPass int, err error) {
120+
testSummary := languageRustTestSummaryRE.FindStringSubmatch(data)
121+
if len(testSummary) == 0 {
122+
return 0, 0, pkgerrors.WithMessage(pkgerrors.WithStack(language.ErrCannotParseTestSummary), data)
123+
}
124+
125+
testsTotal, err = strconv.Atoi(testSummary[1])
126+
if err != nil {
127+
return 0, 0, pkgerrors.WithStack(err)
128+
}
129+
130+
testsPass, err = strconv.Atoi(testSummary[2])
131+
if err != nil {
132+
return 0, 0, pkgerrors.WithStack(err)
133+
}
134+
135+
return testsTotal, testsPass, nil
136+
}
137+
138+
// Mistakes builds a Rust repository and returns the list of mistakes found.
139+
func (l *Language) Mistakes(logger *log.Logger, repositoryPath string) (mistakes []string, err error) {
140+
// TODO
141+
return []string{}, nil
142+
}
143+
144+
// mistakesRe defines the structure of a Rust compiler error.
145+
var mistakesRe = regexp.MustCompile(`(?m)^.*\.rs:\d+:\d+:.*$`)
146+
147+
func extractMistakes(rawMistakes string) (mistakes []string) {
148+
return mistakesRe.FindAllString(rawMistakes, -1)
149+
}
150+
151+
// SupportsFix reports if the language is supported by "symflower fix".
152+
func (l *Language) SupportsFix() bool {
153+
return false
154+
}
155+
156+
// SupportsTemplate reports if the language is supported by "symflower unit-test-skeleton".
157+
func (l *Language) SupportsTemplate() bool {
158+
return false
159+
}

language/testing/Language_mock_gen.go

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)