Skip to content

Commit 35f10f2

Browse files
Make 1.20 fast (#103)
1 parent 3926fbd commit 35f10f2

File tree

10 files changed

+49
-42
lines changed

10 files changed

+49
-42
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
- name: Install Go
1010
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9
1111
with:
12-
go-version: 1.19.x
12+
go-version: 1.20.x
1313
- name: Checkout code
1414
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
1515
- name: Run linters
@@ -27,7 +27,7 @@ jobs:
2727
if: success()
2828
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9
2929
with:
30-
go-version: 1.19.x
30+
go-version: 1.20.x
3131
- name: Checkout code
3232
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
3333
- name: Run tests
@@ -40,7 +40,7 @@ jobs:
4040
if: success()
4141
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9
4242
with:
43-
go-version: 1.19.x
43+
go-version: 1.20.x
4444
- name: Checkout code
4545
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
4646
- name: Calc coverage

Dockerfile

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
1-
FROM golang:1.19.7-alpine3.17
1+
FROM golang:1.20.2-alpine3.17
22

3-
# add addtional packages needed for the race detector to work
4-
RUN apk add --update build-base make
3+
# Add addtional packages needed for the race detector to work
4+
RUN apk add --update build-base make
55

6-
# add a non-root user to run our code as
7-
RUN adduser --disabled-password --gecos "" appuser
6+
# Add a non-root user to run our code as
7+
RUN adduser --disabled-password appuser
88

9-
WORKDIR /opt/test-runner
10-
COPY . .
9+
# Copy the source code into the container
10+
# and make sure appuser owns all of it
11+
COPY --chown=appuser:appuser . /opt/test-runner
12+
13+
# Build and run the testrunner with appuser
14+
USER appuser
15+
16+
# This populates the build cache with the standard library
17+
# and command packages so future compilations are faster
18+
RUN go build std cmd
1119

1220
# Install external packages
1321
WORKDIR /opt/test-runner/external-packages
1422
RUN go mod download
23+
# Populate the build cache with the external packages
24+
RUN go build ./...
1525

1626
# Build the test runner
1727
WORKDIR /opt/test-runner
18-
RUN GOOS=linux GOARCH=amd64 go build -o /opt/test-runner/bin/test-runner /opt/test-runner
19-
20-
USER appuser
21-
ENV GOCACHE=/tmp
28+
RUN go build -o /opt/test-runner/bin/test-runner /opt/test-runner
2229

2330
ENTRYPOINT ["sh", "/opt/test-runner/bin/run.sh"]

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This is [Exercism's test runner](https://github.com/exercism/v3-docs/tree/master
88
## Executing the Test Runner
99

1010
The test runner requires 2 parameters:
11+
1112
- `input_dir`: the path containing the solution to test
1213
- `output_dir`: the output path for the test results
1314

@@ -59,7 +60,7 @@ For troubleshooting / debug you can name the container, run it in interactive mo
5960
```bash
6061
docker run --name exercism-go-test-runner -d -i --network none --read-only -v $(pwd)/testrunner/testdata/practice/gigasecond:/solution -v /tmp:/tmp exercism/go-test-runner gigasecond /solution /tmp
6162
# You can then access the container as follows:
62-
docker exec -it --user appuser $(docker ps -q --filter name=exercism-go-test-runner) /bin/sh
63+
docker exec -it $(docker ps -q --filter name=exercism-go-test-runner) /bin/sh
6364
```
6465

6566
### External Go packages
@@ -81,19 +82,19 @@ A student can have a `go.mod` file declaring only supported dependencies, but if
8182

8283
## Subtests
8384

84-
The test runner is responsible for [returning the `test_code` field](https://github.com/exercism/v3-docs/blob/master/anatomy/track-tooling/test-runners/interface.md#command), which should be a copy of the test code corresponding to each test result.
85+
The test runner is responsible for [returning the `test_code` field](https://github.com/exercism/v3-docs/blob/master/anatomy/track-tooling/test-runners/interface.md#command), which should be a copy of the test code corresponding to each test result.
8586

86-
For top-level tests, the AST is used to return the function code directly. For [tests containing subtests](https://blog.golang.org/subtests), additional processing is required. To ease the burden of advanced AST processing on unstructured / non deterministic test code, subtests should adhere to the following specification. **If a test employs subtests, do not mix it with test or other code outside of the Run() call.**
87+
For top-level tests, the AST is used to return the function code directly. For [tests containing subtests](https://blog.golang.org/subtests), additional processing is required. To ease the burden of advanced AST processing on unstructured / non deterministic test code, subtests should adhere to the following specification. **If a test employs subtests, do not mix it with test or other code outside of the Run() call.**
8788

8889
- Subtests not meeting the spec will be treated as top-level tests, with the entire test function code being returned for every subtest.
8990
- Assertions/outputs made outside of the Run() call will not be included in the result JSON because the "parent" tests are removed from the results if subtests are present. (Parent test reports were confusing to students because they did not include any assertion or `fmt.Println` output.)
9091

9192
At some point, we may [implement a static analyzer](https://rauljordan.com/2020/11/01/custom-static-analysis-in-go-part-1.html) which warns the exercise submitter when they commit subtests not meeting the specification.
9293

93-
9494
### Subtest Format Specification
9595

9696
The specification is annotated in the comments of the following example test:
97+
9798
```go
9899
func TestParseCard(t *testing.T) {
99100
// There can be additional code here, it will be shown for all subtests.
@@ -138,6 +139,7 @@ func TestParseCard(t *testing.T) {
138139
```
139140

140141
The test code above will result in the following `test_code` field, corresponding to the test named `TestParseCard/parse_queen`:
142+
141143
```go
142144
tt := struct {
143145
name string
@@ -162,9 +164,7 @@ This is done via the `.meta/config.json` file of the exercise. See example below
162164
{
163165
// ...
164166
"custom": {
165-
"testingFlags": [
166-
"-race"
167-
]
167+
"testingFlags": ["-race"]
168168
}
169169
}
170170
```
@@ -234,4 +234,4 @@ Besides what is mentioned in the open issues, the test runner has the following
234234
- Sub-tests need to follow a certain format, see details above.
235235

236236
[task-id]: https://exercism.org/docs/building/tooling/test-runners/interface#h-task-id
237-
[task-id-comments-examples]: https://github.com/exercism/go-test-runner/tree/main/testrunner/testdata/concept/conditionals-with-task-ids
237+
[task-id-comments-examples]: https://github.com/exercism/go-test-runner/tree/main/testrunner/testdata/concept/conditionals-with-task-ids

testrunner/testdata/expected/auto_assigned_task_ids.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,35 @@
1313
"name": "TestSimpleSubtest/ parse ace",
1414
"status": "pass",
1515
"test_code": "func TestSimpleSubtest(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse ace\",\n\t\tcard: \"ace\",\n\t\twant: 11,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
16-
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n --- PASS: TestSimpleSubtest/parse_ace \n",
16+
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n--- PASS: TestSimpleSubtest/parse_ace \n",
1717
"task_id": 2
1818
},
1919
{
2020
"name": "TestParseCard/ parse two",
2121
"status": "pass",
2222
"test_code": "func TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse two\",\n\t\tcard: \"two\",\n\t\twant: 2,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
23-
"message": "\n=== RUN TestParseCard/parse_two\n\n --- PASS: TestParseCard/parse_two \n",
23+
"message": "\n=== RUN TestParseCard/parse_two\n\n--- PASS: TestParseCard/parse_two \n",
2424
"task_id": 3
2525
},
2626
{
2727
"name": "TestParseCard/ parse jack",
2828
"status": "pass",
2929
"test_code": "func TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse jack\",\n\t\tcard: \"jack\",\n\t\twant: 10,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
30-
"message": "\n=== RUN TestParseCard/parse_jack\n\n --- PASS: TestParseCard/parse_jack \n",
30+
"message": "\n=== RUN TestParseCard/parse_jack\n\n--- PASS: TestParseCard/parse_jack \n",
3131
"task_id": 3
3232
},
3333
{
3434
"name": "TestParseCard/ parse king",
3535
"status": "pass",
3636
"test_code": "func TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse king\",\n\t\tcard: \"king\",\n\t\twant: 10,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
37-
"message": "\n=== RUN TestParseCard/parse_king\n\n --- PASS: TestParseCard/parse_king \n",
37+
"message": "\n=== RUN TestParseCard/parse_king\n\n--- PASS: TestParseCard/parse_king \n",
3838
"task_id": 3
3939
},
4040
{
4141
"name": "TestBlackjack/ blackjack with ten (ace first)",
4242
"status": "fail",
4343
"test_code": "func TestBlackjack(t *testing.T) {\n\tsomeAssignment := \"test\"\n\tfmt.Println(someAssignment)\n\n\ttype hand struct {\n\t\tcard1, card2 string\n\t}\n\ttt := struct {\n\t\tname string\n\t\thand hand\n\t\twant bool\n\t}{\n\t\tname: \"blackjack with ten (ace first)\",\n\t\thand: hand{card1: \"ace\", card2: \"ten\"},\n\t\twant: true,\n\t}\n\n\t_ = \"literally anything\"\n\n\tgot := IsBlackjack(tt.hand.card1, tt.hand.card2)\n\tif got != tt.want {\n\t\tt.Errorf(\"IsBlackjack(%s, %s) = %t, want %t\", tt.hand.card1, tt.hand.card2, got, tt.want)\n\t}\n\n\t// Additional statements should be included\n\tfmt.Println(\"the whole block\")\n\tfmt.Println(\"should be returned\")\n}",
44-
"message": "\n=== RUN TestBlackjack/blackjack_with_ten_(ace_first)\n\n --- FAIL: TestBlackjack/blackjack_with_ten_(ace_first) \n\npanic: Please implement the IsBlackjack function [recovered]\n\n\tpanic: Please implement the IsBlackjack function\n\n\n\ngoroutine x [running]:\n\ntesting.tRunner.func1.2({, })\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ntesting.tRunner.func1()\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\npanic({, })\n\n\tPATH_PLACEHOLDER/src/runtime/panic.go \n\nconditionals.IsBlackjack(...)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/auto_assigned_task_ids/conditionals.go\n\nconditionals.TestBlackjack.func1?)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/auto_assigned_task_ids/conditionals_test.go \n\ntesting.tRunner, \n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ncreated by testing.(*T).Run\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n",
44+
"message": "\n=== RUN TestBlackjack/blackjack_with_ten_(ace_first)\n\n--- FAIL: TestBlackjack/blackjack_with_ten_(ace_first) \n\npanic: Please implement the IsBlackjack function [recovered]\n\n\tpanic: Please implement the IsBlackjack function\n\n\n\ngoroutine x [running]:\n\ntesting.tRunner.func1.2({, })\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ntesting.tRunner.func1()\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\npanic({, })\n\n\tPATH_PLACEHOLDER/src/runtime/panic.go \n\nconditionals.IsBlackjack(...)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/auto_assigned_task_ids/conditionals.go\n\nconditionals.TestBlackjack.func1?)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/auto_assigned_task_ids/conditionals_test.go \n\ntesting.tRunner, \n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ncreated by testing.(*T).Run\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n",
4545
"task_id": 4
4646
}
4747
]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"status": "error",
33
"version": 3,
4-
"message": "# gigasecond [gigasecond.test]\n./broken.go: undefined: unknownVar\n./broken.go: undefined: UnknownFunction\nFAIL\tgigasecond [build failed]\n'PATH_PLACEHOLDER test --short --json .' returned exit code 2: exit status 2",
4+
"message": "# gigasecond [gigasecond.test]\n./broken.go: undefined: unknownVar\n./broken.go: undefined: UnknownFunction\nFAIL\tgigasecond [build failed]\n'PATH_PLACEHOLDER test --short --json .' returned exit code 1: exit status 1",
55
"tests": null
66
}

testrunner/testdata/expected/explicit_task_ids.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,42 +13,42 @@
1313
"name": "TestSimpleSubtest/ parse ace",
1414
"status": "pass",
1515
"test_code": "// Some other comment\n// testRunnerTaskID=2\nfunc TestSimpleSubtest(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse ace\",\n\t\tcard: \"ace\",\n\t\twant: 11,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
16-
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n --- PASS: TestSimpleSubtest/parse_ace \n",
16+
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n--- PASS: TestSimpleSubtest/parse_ace \n",
1717
"task_id": 2
1818
},
1919
{
2020
"name": "TestSimpleSubtest2/ parse ace",
2121
"status": "pass",
2222
"test_code": "// testRunnerTaskID=2 More text here\nfunc TestSimpleSubtest2(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse ace\",\n\t\tcard: \"ace\",\n\t\twant: 11,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
23-
"message": "\n=== RUN TestSimpleSubtest2/parse_ace\n\n --- PASS: TestSimpleSubtest2/parse_ace \n",
23+
"message": "\n=== RUN TestSimpleSubtest2/parse_ace\n\n--- PASS: TestSimpleSubtest2/parse_ace \n",
2424
"task_id": 2
2525
},
2626
{
2727
"name": "TestParseCard/ parse two",
2828
"status": "pass",
2929
"test_code": "// testRunnerTaskID=1\n// Some other comment\nfunc TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse two\",\n\t\tcard: \"two\",\n\t\twant: 2,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
30-
"message": "\n=== RUN TestParseCard/parse_two\n\n --- PASS: TestParseCard/parse_two \n",
30+
"message": "\n=== RUN TestParseCard/parse_two\n\n--- PASS: TestParseCard/parse_two \n",
3131
"task_id": 1
3232
},
3333
{
3434
"name": "TestParseCard/ parse jack",
3535
"status": "pass",
3636
"test_code": "// testRunnerTaskID=1\n// Some other comment\nfunc TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse jack\",\n\t\tcard: \"jack\",\n\t\twant: 10,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
37-
"message": "\n=== RUN TestParseCard/parse_jack\n\n --- PASS: TestParseCard/parse_jack \n",
37+
"message": "\n=== RUN TestParseCard/parse_jack\n\n--- PASS: TestParseCard/parse_jack \n",
3838
"task_id": 1
3939
},
4040
{
4141
"name": "TestParseCard/ parse king",
4242
"status": "pass",
4343
"test_code": "// testRunnerTaskID=1\n// Some other comment\nfunc TestParseCard(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse king\",\n\t\tcard: \"king\",\n\t\twant: 10,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
44-
"message": "\n=== RUN TestParseCard/parse_king\n\n --- PASS: TestParseCard/parse_king \n",
44+
"message": "\n=== RUN TestParseCard/parse_king\n\n--- PASS: TestParseCard/parse_king \n",
4545
"task_id": 1
4646
},
4747
{
4848
"name": "TestBlackjack/ blackjack with ten (ace first)",
4949
"status": "fail",
5050
"test_code": "// testRunnerTaskID=3\nfunc TestBlackjack(t *testing.T) {\n\tsomeAssignment := \"test\"\n\tfmt.Println(someAssignment)\n\n\ttype hand struct {\n\t\tcard1, card2 string\n\t}\n\ttt := struct {\n\t\tname string\n\t\thand hand\n\t\twant bool\n\t}{\n\t\tname: \"blackjack with ten (ace first)\",\n\t\thand: hand{card1: \"ace\", card2: \"ten\"},\n\t\twant: true,\n\t}\n\n\t_ = \"literally anything\"\n\n\tgot := IsBlackjack(tt.hand.card1, tt.hand.card2)\n\tif got != tt.want {\n\t\tt.Errorf(\"IsBlackjack(%s, %s) = %t, want %t\", tt.hand.card1, tt.hand.card2, got, tt.want)\n\t}\n\n\t// Additional statements should be included\n\tfmt.Println(\"the whole block\")\n\tfmt.Println(\"should be returned\")\n}",
51-
"message": "\n=== RUN TestBlackjack/blackjack_with_ten_(ace_first)\n\n --- FAIL: TestBlackjack/blackjack_with_ten_(ace_first) \n\npanic: Please implement the IsBlackjack function [recovered]\n\n\tpanic: Please implement the IsBlackjack function\n\n\n\ngoroutine x [running]:\n\ntesting.tRunner.func1.2({, })\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ntesting.tRunner.func1()\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\npanic({, })\n\n\tPATH_PLACEHOLDER/src/runtime/panic.go \n\nconditionals.IsBlackjack(...)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/explicit_task_ids/conditionals.go\n\nconditionals.TestBlackjack.func1?)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/explicit_task_ids/conditionals_test.go \n\ntesting.tRunner, \n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ncreated by testing.(*T).Run\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n",
51+
"message": "\n=== RUN TestBlackjack/blackjack_with_ten_(ace_first)\n\n--- FAIL: TestBlackjack/blackjack_with_ten_(ace_first) \n\npanic: Please implement the IsBlackjack function [recovered]\n\n\tpanic: Please implement the IsBlackjack function\n\n\n\ngoroutine x [running]:\n\ntesting.tRunner.func1.2({, })\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ntesting.tRunner.func1()\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\npanic({, })\n\n\tPATH_PLACEHOLDER/src/runtime/panic.go \n\nconditionals.IsBlackjack(...)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/explicit_task_ids/conditionals.go\n\nconditionals.TestBlackjack.func1?)\n\n\tPATH_PLACEHOLDER/testrunner/testdata/concept/explicit_task_ids/conditionals_test.go \n\ntesting.tRunner, \n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n\ncreated by testing.(*T).Run\n\n\tPATH_PLACEHOLDER/src/testing/testing.go \n",
5252
"task_id": 3
5353
}
5454
]
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"status": "error",
33
"version": 3,
4-
"message": "# gigasecond [gigasecond.test]\n./missing_func_test.go: undefined: AddGigasecond\n./missing_func_test.go: undefined: AddGigasecond\nFAIL\tgigasecond [build failed]\n'PATH_PLACEHOLDER test --short --json .' returned exit code 2: exit status 2",
4+
"message": "# gigasecond [gigasecond.test]\n./missing_func_test.go: undefined: AddGigasecond\n./missing_func_test.go: undefined: AddGigasecond\nFAIL\tgigasecond [build failed]\n'PATH_PLACEHOLDER test --short --json .' returned exit code 1: exit status 1",
55
"tests": null
66
}

testrunner/testdata/expected/missing_task_ids.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"name": "TestSimpleSubtest/ parse ace",
1313
"status": "pass",
1414
"test_code": "// testRunnerTaskID=1\nfunc TestSimpleSubtest(t *testing.T) {\n\ttt := struct {\n\t\tname string\n\t\tcard string\n\t\twant int\n\t}{\n\t\tname: \"parse ace\",\n\t\tcard: \"ace\",\n\t\twant: 11,\n\t}\n\n\tif got := ParseCard(tt.card); got != tt.want {\n\t\tt.Errorf(\"ParseCard(%s) = %d, want %d\", tt.card, got, tt.want)\n\t}\n\n}",
15-
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n --- PASS: TestSimpleSubtest/parse_ace \n"
15+
"message": "\n=== RUN TestSimpleSubtest/parse_ace\n\n--- PASS: TestSimpleSubtest/parse_ace \n"
1616
}
1717
]
1818
}

0 commit comments

Comments
 (0)