Exercism Go Track

Exercism exercises in Go
Issues
We welcome issues filed at https://github.com/exercism/go/issues for problems of any size. Feel free to report
typographical errors or poor wording. We are most interested in improving the quality of the test suites.
You can greatly help us improve the quality of the exercises by filing reports of invalid solutions that
pass tests or of valid solutions that fail tests.
Development setup
Beyond filing issues, if you would like to contribute directly to the Go code in the Exercism Go track, you should follow some
standard Go development practices. You should have a recent version of Go
installed, ideally either the current release, the previous release, or tip.
You will need a github account and you will need to fork exercism/go to your account.
See GitHub Help if you are unfamiliar with the process.
Clone your fork with the command: git clone https://github.com/<you>/go
.
Test your clone by cding to the go directory and typing
bin/test-without-stubs
. You should see tests pass for all exercises.
Note that unlike most other Go code, it is not necessary to clone this to your GOPATH.
This is because this repo only imports from the standard library and isn't expected to be imported by other packages.
Your Go code should be formatted using the gofmt tool. For the other file types in the repository you may want to copy the setup used in the .editorconfig file from the exercism.io repository.
There is a misspelling tool. You can install and occasionally run it to
find low hanging typo problems. #570 It's not added into CI since it could give false positives.
Contributing Guide
Please be familiar with the contributing guide
in the docs repository. This describes some great ways to get involved.
In particular, please read the Pull Request Guidelines before opening a pull request.
Exercism Go style
Let's walk through an example, non-existent, exercise, which we'll call fizzbuzz
to see what could be included in its implementation.
In any exercise you may see a number of files present:
~/exercism/go/fizzbuzz
$ tree -a
.
├── cases_test.go
├── example.go
├── fizzbuzz.go
├── fizzbuzz_test.go
├── .meta
│ └── description.md
│ └── gen.go
│ └── hints.md
│ └── metadata.yml
└── README.md
This list of files can vary across exercises. Not all exercises use
all of these files. Exercises originate their test data and README
text from the Exercism problem-specification repository.
This repository collects common information for all exercises across all
tracks. However, should track-specific documentation need to be
included with the exercise, files in an exercise's .meta/
directory
can be used to override or augment the exercise's README.
So let's quickly run through each file and briefly describe it:
-
cases_test.go - This file contains generated test cases,
and will only be present in some exercises. These will be
automatically generated by a .meta/gen.go file and should
represent test data sourced from the problem-specifications repository.
-
example.go - This is an example solution for
the exercise. It is used to verify the test suite and to provide a
reference example of a solution to the exercise. This file is ignored
by the exercism fetch
command. See ignored files
for details on which files are ignored.
-
fizzbuzz.go - This is a stub file, and will only be
present in some exercises as a way to give users a useful starting
point.
-
fizzbuzz_test.go - This is the main test file for the
exercise.
-
.meta/ - The .meta/
directory contains files that are not
to be included when a user fetches an exercise: test case generators
and README inclusion files. These files are for tooling and will not
be present for users of the exercise. (Again, see ignored files.)
-
.meta/description.md - This file, along with some others (below)
in the .meta
directory are used to generate exercise specific elements
of the exercise's README.md file. Any content in this file will
completely override the description.md of the exercise from the
problem-specifications repository.
-
.meta/gen.go - This file, unique within the .meta
directory,
generates the cases_test.go file. This will only be present in some
exercises that have problem-specification test data. If so this
generator is used to transform the test data into a format suitable
for the exercise. See generating test cases
for more information.
-
.meta/hints.md - This is another README related file, it should
be used for the inclusion of any track specific information beyond
what would be present in a generic exercise's problem-specification
description.
-
.meta/metadata.yml - Like the meta/*.md
files, this will
override the exercise metadata from the problem-specifications
repository.
In some exercises there can be extra files, for instance the
series exercise contains extra test files.
Ignored files
When a user fetches an exercise, they do not need to get all the files within an
exercise directory. For instance; the example.go files that contain an
example solution, or the gen.go files used to generate an exercise's test
cases. Therefore there are certain files and directories that are ignored when
an exercise is fetched. These are:
- The .meta directory and anything within it.
- Any file that matches the
ignore_pattern
defined in the config.json file.
This currently matches any filename that contains the word example
, unless
it is followed by the word test
, with any number of characters inbetween.
Example solutions
example.go is a reference solution. It is a valid solution that Travis,
the CI (continuous integration) service, can run tests against. Solvers generally
will not see it though. Files with "example" in the file name are skipped by
the exercism fetch
command. Because of this, there is less need for this code
to be a model of style, expression and readability, or to use the best algorithm.
Examples can be plain, simple, concise, even naïve, as long as they are correct.
The test file though, is fetched for the solver and deserves attention for consistency
and appearance.
Tests
The leap
exercise makes use of data-driven tests. Test cases are defined as
data, then a test function iterates over the data. In this exercise, as they are
generated, the test cases are defined in the cases_test.go file. The test function
that iterates over this data is defined in the leap_test.go file.
Identifiers within the test function appear in actual-expected order as described
at Useful Test Failures.
Here the identifier observed
is used instead of actual. That's fine. More
common are words got
and want
. They are clear and short. Note Useful Test
Failures
is part of Code Review Comments.
Really we like most of the advice on that page.
In Go we generally have all tests enabled and do not ask the solver to edit the
test program, to enable progressive tests for example. t.Fatalf()
, as seen
in the leap_test.go file, will stop tests at the first failure encountered,
so the solver is not faced with too many failures all at once.
Benchmarks
In most test files there will also be benchmark tests, as can be seen at the end
of the leap_test.go file. In Go, benchmarking is a first-class citizen of the
testing package. We throw in benchmarks because they're interesting, and because
it is idiomatic in Go to think about performance. There is no critical use for
these though. Usually they will just bench the combined time to run over all
the test data rather than attempt precise timings on single function calls. They
are useful if they let the solver try a change and see a performance effect.
Testable examples
Some exercises can contain Example tests
that document the exercise API. These examples are run alongside the standard
exercise tests and will verify that the exercise API is working as expected.
They are not required by all exercises and are not intended to replace the
data-driven tests. They are most useful for providing examples of how an
exercise's API is used. Have a look at the example tests in the clock exercise
to see them in action.
Stub files
Stub files, such as leap.go, are a starting point for solutions. Not all exercises
need to do this; this is most helpful in the early exercises for newcomers to Go.
By convention, the stub file for an exercise with slug exercise-slug
must be named exercise_slug.go
. This is because CI needs to delete stub files
to avoid conflicting definitions.
The track exercises may or may not provide stub files. The first few exercises
provide stubs as a helpful starting point. The initial exercise users will encounter
without a stub is twelve-days. At this point users will
have some experience in creating solutions for the exercises and can begin to
create their own solutions from scratch. Some of the later exercises may have stub
files if the author thinks there may be implementation confusion, a particularly
difficult concept, or boilerplate code needed.
Errors
We like errors in Go. It's not idiomatic Go to ignore invalid data or have undefined
behavior. Sometimes our Go tests require an error return where other language
tracks don't.
Generating test cases
Some problems that are implemented in multiple tracks use the same inputs and
outputs to define the test suites. Where the problem-specifications
repository contains a canonical-data.json file with these inputs and outputs,
we can generate the test cases programmatically.
See the gen.go file in the leap
exercise for an example of how this
can be done.
Test case generators are named gen.go and are kept in a special .meta
directory within each exercise that makes use of a test cases generator. This
.meta directory will be ignored when a user fetches an exercise.
Whenever the shared JSON data changes, the test cases will need to be regenerated.
The generator will first look for a local copy of the problem-specifications repository.
If there isn't one it will attempt to get the relevant json data for the
exercise from the problem-specifications repository on GitHub.
To use a local copy of the problem-specifications repository, make sure that it has been
cloned into the same parent-directory as the go repository.
$ tree -L 1 .
.
├── problem-specifications
└── go
To regenerate the test cases, navigate into the go directory and run
go run exercises/<exercise>/.meta/gen.go
. You should see that the
<exercise>/cases_test.go
file has changed. Commit the change.
Pull requests
Pull requests are welcome. You forked, cloned, coded and tested and you have something good? Awesome! Use git
to add, commit, and push to your repository. Checkout your repository on the web now. You should see your commit
and the invitation to submit a pull request!
Click on that big green button. You have a chance to add more explanation to your pull request here, then send
it. Looking at the exercism/go repository now instead of your own, you see this.
That inconspicuous orange dot is important! Hover over it (no, not on this image, on a real page) and you can see
it's indicating that a Travis CI build is in progress. After a few minutes (usually) that dot will turn green
indicating that tests passed. If there's a problem, it comes up red:
This means you've still got work to do. Click on "details" to go to the Travis site and look over the build log
for clues. Usually error messages will be helpful and you can correct the problem.
Direction
Directions are unlimited. This code is fresh and evolving. Explore the existing code and you will see some new
directions being tried. Your fresh ideas and contributions are welcome. ✨
Go icon
The Go logo was designed by Renée French, and has been released under the Creative Commons 3.0 Attributions license.