Skip to content

Commit 2e7d80e

Browse files
author
eliastor
committed
added notes for unit1 and auto tests for exercies
1 parent 8f71e9f commit 2e7d80e

File tree

10 files changed

+543
-4
lines changed

10 files changed

+543
-4
lines changed

.ci/go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module tester
2+
3+
go 1.18
4+
5+
require (
6+
github.com/davecgh/go-spew v1.1.0 // indirect
7+
github.com/pmezard/go-difflib v1.0.0 // indirect
8+
github.com/stretchr/testify v1.7.2 // indirect
9+
gopkg.in/yaml.v3 v3.0.1 // indirect
10+
)

.ci/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6+
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
7+
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

.ci/unit1/e0_test.go

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package unit1
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"go/ast"
7+
"go/parser"
8+
"go/token"
9+
"io"
10+
"math"
11+
"os"
12+
"os/exec"
13+
"strconv"
14+
"strings"
15+
"testing"
16+
17+
"github.com/stretchr/testify/assert"
18+
)
19+
20+
func TestExercise0(t *testing.T) {
21+
codepath := "../../unit1/exercises/e0/main.go"
22+
var callVal string
23+
t.Run("Syntax", newTestExercise0_Syntax(codepath, &callVal))
24+
t.Run("Output", newTestExercise0_Output(codepath, &callVal))
25+
}
26+
27+
func newTestExercise0_Syntax(codepath string, callValue *string) func(t *testing.T) {
28+
29+
return func(t *testing.T) {
30+
sqrtDefinedinMainScope := false
31+
sqrtDefined := false
32+
sqrtArgIsInt := false
33+
sqrtArgIsFloat := false
34+
sqrtArgStringValue := ""
35+
36+
fs := token.NewFileSet()
37+
f, err := parser.ParseFile(fs, codepath, nil, parser.AllErrors)
38+
if err != nil {
39+
t.Fatal("can't open file for parsing:", err)
40+
}
41+
42+
ast.Inspect(f, func(n ast.Node) bool {
43+
if n == nil {
44+
return false
45+
}
46+
// t.Log(n, fmt.Sprintf("%T", n))
47+
funcDecl, ok := n.(*ast.FuncDecl)
48+
if ok {
49+
if funcDecl.Name.Name == "Sqrt" {
50+
sqrtDefined = true
51+
return true
52+
}
53+
}
54+
callExpr, ok := n.(*ast.CallExpr)
55+
if ok {
56+
ident, ok := (callExpr.Fun).(*ast.Ident)
57+
if ok {
58+
if ident.String() == "Sqrt" {
59+
if !assert.Equal(t, 1, len(callExpr.Args), "wrong number of arguments in Sqrt call") {
60+
return false
61+
}
62+
arg := callExpr.Args[0]
63+
basicLit, ok := arg.(*ast.BasicLit)
64+
if ok {
65+
switch basicLit.Kind {
66+
case token.INT:
67+
sqrtArgIsInt = true
68+
sqrtArgStringValue = basicLit.Value
69+
case token.FLOAT:
70+
sqrtArgIsFloat = true
71+
sqrtArgStringValue = basicLit.Value
72+
default:
73+
assert.Fail(t, "Argument for Sqrt call must be a number")
74+
return false
75+
}
76+
}
77+
}
78+
}
79+
80+
}
81+
82+
return true
83+
})
84+
85+
for _, obj := range f.Scope.Objects {
86+
if obj.Kind == ast.Fun && obj.Name == "Sqrt" {
87+
sqrtDefinedinMainScope = true
88+
}
89+
}
90+
91+
assert.True(t, sqrtDefined, "Sqrt function is not defined")
92+
assert.True(t, sqrtDefinedinMainScope, "Sqrt function is not defined in main package")
93+
assert.True(t, sqrtArgIsFloat || sqrtArgIsInt, "Sqrt argument argument in Sqrt call must be a number")
94+
assert.NotEmpty(t, sqrtArgStringValue, "Sqart call argument must not be empty")
95+
96+
*callValue = sqrtArgStringValue
97+
}
98+
}
99+
func newTestExercise0_Output(codepath string, callValue *string) func(t *testing.T) {
100+
return func(t *testing.T) {
101+
if !assert.NotNil(t, callValue, "cellValue must not be empty") {
102+
assert.FailNow(t, "test error: cellValue is empty")
103+
}
104+
t.Log("Trying to build and run file:", codepath)
105+
106+
cmd := exec.Command("timeout", "10", "go", "run", codepath)
107+
tmpDir, err := os.MkdirTemp("", "gotest-*")
108+
if !assert.NoError(t, err) {
109+
assert.FailNow(t, "test error: cannot create temporary dir")
110+
}
111+
defer os.RemoveAll(tmpDir)
112+
113+
cmd.Env = []string{
114+
"PATH=" + os.Getenv("PATH"),
115+
"CGO_ENABLED=0",
116+
"GOCACHE=" + tmpDir,
117+
}
118+
119+
outBuf := bytes.NewBuffer(nil)
120+
errBuf := bytes.NewBuffer(nil)
121+
cmd.Stdout = outBuf
122+
cmd.Stderr = errBuf
123+
124+
err = cmd.Run()
125+
if !assert.NoError(t, err, errBuf.String()) {
126+
assert.FailNow(t, "test error: \"go run\" failed", err)
127+
return
128+
}
129+
130+
assert.NoError(t, err, "Can't compile and run code")
131+
assert.Empty(t, errBuf.String(), "stderr of your code must be empty", errBuf.String())
132+
assert.NotEmpty(t, outBuf.String(), "stdout of your code must not be empty")
133+
134+
arg, err := strconv.ParseFloat(*callValue, 64)
135+
if !assert.NoError(t, err) {
136+
assert.FailNow(t, "test error: cannot parse Sqrt argument value:", err)
137+
}
138+
139+
epsilon := 0.0000000001
140+
141+
prevVal := arg
142+
curVal := 0.0
143+
sqroot := math.Sqrt(arg)
144+
145+
bfr := bufio.NewReader(outBuf)
146+
for {
147+
line, err := bfr.ReadString('\n')
148+
if err != nil && err != io.EOF {
149+
assert.FailNow(t, "test error: can't read output buffer", err)
150+
break
151+
}
152+
line = strings.TrimRight(line, "\r\n")
153+
if line == "" && err != io.EOF {
154+
continue
155+
}
156+
if err == io.EOF {
157+
break
158+
}
159+
curVal, err = strconv.ParseFloat(line, 64)
160+
if !assert.NoError(t, err) {
161+
assert.FailNow(t, "test error: cannot parse output line to number:", err)
162+
}
163+
assert.Greater(t, prevVal, curVal, "seems to be your code has error, previous iteration is less than following iteration", prevVal, curVal)
164+
assert.Greater(t, math.Abs(prevVal-curVal), epsilon, "seems to be your code stucked around one value", prevVal, curVal)
165+
}
166+
assert.Less(t, sqroot-curVal, epsilon, "seems to be your code has wrong computations, result value is far from real", sqroot, curVal)
167+
}
168+
}

.ci/unit1/e1_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package unit1
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"os/exec"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestExercise1_Syntax(t *testing.T) {
13+
}
14+
15+
func TestExercise1_Output(t *testing.T) {
16+
expected := `0
17+
1
18+
1
19+
2
20+
3
21+
5
22+
8
23+
13
24+
21
25+
34
26+
`
27+
28+
codepath := "../../unit1/exercises/e1/main.go"
29+
30+
cmd := exec.Command("timeout", "10", "go", "run", codepath)
31+
tmpDir, err := os.MkdirTemp("", "gotest-*")
32+
if !assert.NoError(t, err) {
33+
assert.FailNow(t, "test error: cannot create temporary dir")
34+
}
35+
defer os.RemoveAll(tmpDir)
36+
37+
cmd.Env = []string{
38+
"PATH=" + os.Getenv("PATH"),
39+
"CGO_ENABLED=0",
40+
"GOCACHE=" + tmpDir,
41+
}
42+
43+
outBuf := bytes.NewBuffer(nil)
44+
errBuf := bytes.NewBuffer(nil)
45+
cmd.Stdout = outBuf
46+
cmd.Stderr = errBuf
47+
48+
err = cmd.Run()
49+
if !assert.NoError(t, err, errBuf.String()) {
50+
assert.FailNow(t, "test error: \"go run\" failed", err)
51+
return
52+
}
53+
54+
assert.NoError(t, err, "Can't compile and run code")
55+
assert.Empty(t, errBuf.String(), "stderr of your code must be empty", errBuf.String())
56+
assert.NotEmpty(t, outBuf.String(), "stdout of your code must not be empty")
57+
58+
assert.Equal(t, expected, outBuf.String())
59+
}

.ci/unit1/e2_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package unit1
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"os/exec"
7+
"strings"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestExercise2_Syntax(t *testing.T) {
14+
}
15+
16+
func TestExercise2_Output(t *testing.T) {
17+
expected := `googleDNS: 8.8.8.8
18+
loopback: 127.0.0.1
19+
`
20+
21+
codepath := "../../unit1/exercises/e2/main.go"
22+
23+
cmd := exec.Command("timeout", "10", "go", "run", codepath)
24+
tmpDir, err := os.MkdirTemp("", "gotest-*")
25+
if !assert.NoError(t, err) {
26+
assert.FailNow(t, "test error: cannot create temporary dir")
27+
}
28+
defer os.RemoveAll(tmpDir)
29+
30+
cmd.Env = []string{
31+
"PATH=" + os.Getenv("PATH"),
32+
"CGO_ENABLED=0",
33+
"GOCACHE=" + tmpDir,
34+
}
35+
36+
outBuf := bytes.NewBuffer(nil)
37+
errBuf := bytes.NewBuffer(nil)
38+
cmd.Stdout = outBuf
39+
cmd.Stderr = errBuf
40+
41+
err = cmd.Run()
42+
if !assert.NoError(t, err, errBuf.String()) {
43+
assert.FailNow(t, "test error: \"go run\" failed", err)
44+
return
45+
}
46+
47+
assert.NoError(t, err, "Can't compile and run code")
48+
assert.Empty(t, errBuf.String(), "stderr of your code must be empty", errBuf.String())
49+
assert.NotEmpty(t, outBuf.String(), "stdout of your code must not be empty")
50+
51+
outputLines := strings.Split(outBuf.String(), "\n")
52+
expectedLines := strings.Split(expected, "\n")
53+
assert.Subset(t, outputLines, expectedLines, "not all lines are printed")
54+
assert.Subset(t, expectedLines, outputLines, "odd lines are printed")
55+
}

.ci/unit1/e3_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package unit1
2+
3+
import (
4+
"bytes"
5+
"os"
6+
"os/exec"
7+
"strings"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestExercise3_Syntax(t *testing.T) {
14+
}
15+
16+
func TestExercise3_Output(t *testing.T) {
17+
codepath := "../../unit1/exercises/e3/main.go"
18+
19+
cmd := exec.Command("timeout", "10", "go", "run", codepath)
20+
tmpDir, err := os.MkdirTemp("", "gotest-*")
21+
if !assert.NoError(t, err) {
22+
assert.FailNow(t, "test error: cannot create temporary dir")
23+
}
24+
defer os.RemoveAll(tmpDir)
25+
26+
cmd.Env = []string{
27+
"PATH=" + os.Getenv("PATH"),
28+
"CGO_ENABLED=0",
29+
"GOCACHE=" + tmpDir,
30+
}
31+
32+
outBuf := bytes.NewBuffer(nil)
33+
errBuf := bytes.NewBuffer(nil)
34+
cmd.Stdout = outBuf
35+
cmd.Stderr = errBuf
36+
37+
err = cmd.Run()
38+
if !assert.NoError(t, err, errBuf.String()) {
39+
assert.FailNow(t, "test error: \"go run\" failed", err)
40+
return
41+
}
42+
43+
assert.NoError(t, err, "Can't compile and run code")
44+
assert.Empty(t, errBuf.String(), "stderr of your code must be empty", errBuf.String())
45+
assert.NotEmpty(t, outBuf.String(), "stdout of your code must not be empty")
46+
47+
outputLines := strings.Split(outBuf.String(), "\n")
48+
if !assert.Equal(t, 3, len(outputLines), "there must be 2 lines with output and one blank line in the stdout") {
49+
t.FailNow()
50+
}
51+
assert.Regexp(t, "^[0-9]+(\\.[0-9]+)? <nil>$", outputLines[0], "first call must return square root and nil error")
52+
assert.Equal(t, "0 cannot Sqrt negative number: -2", outputLines[1], "second call must output error")
53+
assert.Equal(t, "", outputLines[2], "Println must be used, missing last newline")
54+
}

0 commit comments

Comments
 (0)