Skip to content

Commit

Permalink
Added generator and gomod-sync to linters and tests (#2426)
Browse files Browse the repository at this point in the history
  • Loading branch information
eklatzer authored Sep 21, 2022
1 parent b3f1508 commit ac4c831
Show file tree
Hide file tree
Showing 84 changed files with 640 additions and 438 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/exercise-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,28 @@ on:

jobs:
test:
name: Go ${{ matrix.go-version }} - ${{ matrix.os }}/${{ matrix.test-arch }} - ${{ github.event_name }}
name: Go ${{ matrix.go-version }} - ${{ matrix.os }}/${{ matrix.test-arch }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
go-version: [1.18.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
test-arch: [amd64]
race: ['-race']
race: ["-race"]

include:
- go-version: 1.18.x
test-arch: '386'
test-arch: "386"
os: ubuntu-latest
race: ''
race: ""
- go-version: 1.18.x
test-arch: '386'
test-arch: "386"
os: windows-latest
race: ''
race: ""

steps:
- run: git config --global core.autocrlf false
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
Expand All @@ -43,4 +44,4 @@ jobs:
GOARCH: ${{ matrix.test-arch }}
run: |
./bin/fetch-golangci-lint
./bin/test-without-stubs
./bin/run-tests
45 changes: 45 additions & 0 deletions .github/workflows/stub-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Stub tests

on:
workflow_dispatch:
push:
branches:
- main
- master
pull_request:

jobs:
test:
name: Go ${{ matrix.go-version }} - ${{ matrix.os }}/${{ matrix.test-arch }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
go-version: [1.18.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
test-arch: [amd64]
race: ["-race"]

include:
- go-version: 1.18.x
test-arch: "386"
os: ubuntu-latest
race: ""
- go-version: 1.18.x
test-arch: "386"
os: windows-latest
race: ""

steps:
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
with:
go-version: ${{ matrix.go-version }}

- name: Run tests on stubs
shell: bash
env:
GOARCH: ${{ matrix.test-arch }}
run: |
./bin/run-tests test-stubs
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
run:
timeout: 5m
timeout: 8m
linters:
disable-all: true
enable:
Expand Down
76 changes: 69 additions & 7 deletions bin/test-without-stubs → bin/run-tests
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

root=$(pwd)
tmp=tmp/lint
mkdir -p $tmp
rm -rf "$tmp"
mkdir -p "$tmp"

mode="${1:-default}"
TEST_STUBS_MODE="test-stubs"

for parentdir in concept practice; do
for dir in exercises/$parentdir/*/; do
Expand Down Expand Up @@ -50,10 +54,20 @@ EOD
mkdir -p $tmpstub
echo "copy base files and tests to $tmpstub"
cp $dir/*.go $tmpstub
echo "copy exemplar $exemplar to $tmpstub"
cp $exemplar "${tmpstub}/${stub}.go"
if [ "$mode" != "$TEST_STUBS_MODE" ];then
echo "copy exemplar $exemplar to $tmpstub"
cp $exemplar "${tmpstub}/${stub}.go"
fi
echo "copy module $mod to $tmpstub"
cp $mod $tmpstub

generator="${dir}.meta/gen.go"
if [ -f "${generator}" ]; then
# copying generator to be automatically linted when the exercise is linted
echo "copy generator ${generator}"
mkdir -p "${tmp}/gen/${stub}" && cp "${generator}" "${tmp}/gen/${stub}/gen.go"
fi

echo "put everything in the same module"
original_module=`head -n1 $tmpstub/go.mod | awk '{ print $2 }'`
sed -i'.bak' "s|package .*|package ${stub}|" $tmpstub/*.go
Expand Down Expand Up @@ -84,10 +98,58 @@ trap cleanup EXIT INT TERM
# module-aware mode only in places where a go.mod is present.
export GO111MODULE=auto

# This is the last command in the file,
# so the exit status of this script is the exit status of go test.
# If this ever changes, remember to preserve the exit status accordingly.
# Otherwise CI may falsely report a test as passed when it has failed.
if [ "$mode" = "$TEST_STUBS_MODE" ];then
echo "running tests with stubs and expecting tests to fail"
for exercise in ./$tmp/concept/* ./$tmp/practice/*; do
# ignore exercises that have a stub that passes the tests
# deep_thought: no tests
# ledger, markdown: refactoring exercise

if [[ "$exercise" == *"deep_thought"* || "$exercise" == *"ledger"* || "$exercise" == *"markdown"* ]];
then
echo "ignoring $exercise (no tests or refactoring exercise)"
continue;
fi
echo "testing $exercise"
result=$(go test -v "$exercise" 2>&1)
if echo "$result" | grep -q 'PASS'; then
echo "[ERROR] stub at $exercise passed the tests, even thought expect stub to fail"
echo "$result"
exit 1
fi
done
echo "SUCESS"
exit 0
fi

echo "running linter and tests for exercises and exercise generators"
# Run lint which is configured by .golangci.yml at the root of the repo
# and if it's successful, run tests
bin/golangci-lint run ./$tmp/... && go test -cpu 2 ./$tmp/...

exitcode=$?

if [ $exitcode -ne 0 ]
then
echo "LINTER/TESTS FAILED for exercises or exercise generators"
exit $exitcode
fi

echo "SUCCESS"

paths_to_lint="gomod-sync gen"
for path in $paths_to_lint; do
cd "$root"
cd "$path"

echo "running linters and tests for $path/..."
$root/bin/golangci-lint run ./... && go test -cpu 2 ./...

exitcode=$?
if [ $exitcode -ne 0 ]
then
echo "LINTER/TESTS FAILED for $path/..."
exit $exitcode
fi
echo "SUCCESS"
done
2 changes: 1 addition & 1 deletion exercises/practice/acronym/.meta/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
var j = map[string]interface{}{
j := map[string]interface{}{
"abbreviate": &[]testCase{},
}
if err := gen.Gen("acronym", j, t); err != nil {
Expand Down
152 changes: 76 additions & 76 deletions exercises/practice/all-your-base/.meta/gen.go
Original file line number Diff line number Diff line change
@@ -1,76 +1,76 @@
package main

import (
"log"
"text/template"

"../../../../gen"
)

func main() {
t, err := template.New("").Parse(tmpl)
if err != nil {
log.Fatal(err)
}
var j = map[string]interface{}{
"rebase": &[]testCase{},
}
if err := gen.Gen("all-your-base", j, t); err != nil {
log.Fatal(err)
}
}

type testCase struct {
Description string `json:"description"`
Input struct {
InputBase int `json:"inputBase"`
Digits []int `json:"digits"`
OutputBase int `json:"outputBase"`
} `json:"input"`
Expected interface{} `json:"expected"`
}

func (o testCase) Result() []int {
s, ok := o.Expected.([]interface{})
if !ok {
return nil
}
var res []int
for _, v := range s {
f, _ := v.(float64)
res = append(res, int(f))
}
return res
}

func (o testCase) Err() string {
m, ok := o.Expected.(map[string]interface{})
if !ok {
return ""
}
return m["error"].(string)
}

// Template to generate test cases.
var tmpl = `package allyourbase
{{.Header}}
var testCases = []struct {
description string
inputBase int
inputDigits []int
outputBase int
expected []int
expectedError string
}{ {{range .J.rebase}}
{
description: {{printf "%q" .Description}},
inputBase: {{printf "%d" .Input.InputBase}},
inputDigits: {{printf "%#v" .Input.Digits}},
outputBase: {{printf "%d" .Input.OutputBase}},
expected: {{printf "%#v" .Result}},
expectedError: {{printf "%q" .Err}},
},{{end}}
}
`
package main

import (
"log"
"text/template"

"../../../../gen"
)

func main() {
t, err := template.New("").Parse(tmpl)
if err != nil {
log.Fatal(err)
}
j := map[string]interface{}{
"rebase": &[]testCase{},
}
if err := gen.Gen("all-your-base", j, t); err != nil {
log.Fatal(err)
}
}

type testCase struct {
Description string `json:"description"`
Input struct {
InputBase int `json:"inputBase"`
Digits []int `json:"digits"`
OutputBase int `json:"outputBase"`
} `json:"input"`
Expected interface{} `json:"expected"`
}

func (o testCase) Result() []int {
s, ok := o.Expected.([]interface{})
if !ok {
return nil
}
var res []int
for _, v := range s {
f, _ := v.(float64)
res = append(res, int(f))
}
return res
}

func (o testCase) Err() string {
m, ok := o.Expected.(map[string]interface{})
if !ok {
return ""
}
return m["error"].(string)
}

// Template to generate test cases.
var tmpl = `package allyourbase
{{.Header}}
var testCases = []struct {
description string
inputBase int
inputDigits []int
outputBase int
expected []int
expectedError string
}{ {{range .J.rebase}}
{
description: {{printf "%q" .Description}},
inputBase: {{printf "%d" .Input.InputBase}},
inputDigits: {{printf "%#v" .Input.Digits}},
outputBase: {{printf "%d" .Input.OutputBase}},
expected: {{printf "%#v" .Result}},
expectedError: {{printf "%q" .Err}},
},{{end}}
}
`
Loading

0 comments on commit ac4c831

Please sign in to comment.