Go source files in one directory normally form one package. Files declare their package name, and declarations beginning with an uppercase letter are exported. A module is a versioned collection of packages rooted at go.mod. Import paths identify packages; package declarations determine the names used within those files. The words package and module therefore describe different boundaries.
A reusable package normally has no main entry point. A command uses package main and defines main. This course's single-file exercises also use package main, but native testing supplies their executable entry point. That convention keeps the grader small; it is not advice to put every real library into main. The included projects/go-lab has a reusable logsummary package and a separate cmd/logsum command so you can run a genuine multi-package module locally.
Test the contract callers can observe
Native tests live in files ending _test.go, import testing, and expose
functions such as func TestNormalize(t *testing.T). go test compiles the
package and tests before running them. Here, authored tests_public.go and
tests_hidden.go are renamed by the runner to that native suffix. The suites
run independently. The public suite is useful reading; hidden boundaries check
the same stated API without exposing their inputs.
A table-driven test lists inputs and expected results once and runs the same assertion for each case. Name subtests so a failure identifies the relevant case. Include invalid inputs and storage behavior, not just a happy example. Tests should call NormalizeKey and CountKeys rather than requiring your private helper name or reproducing your implementation character by character.
package main
import ("fmt"; "strings")
func main() {
for _, raw := range []string{" API-2 ", "Db", "x_y"} {
fmt.Println(strings.ToLower(strings.TrimSpace(raw)))
}
}Normalization changes representation; validation decides which representations the package accepts. Lowercasing Unicode does not make every resulting rune an allowed ASCII key. Validate the stated alphabet after normalization, and keep the error category stable while adding the failing batch position.
Modules do not require a network exercise
For a standard-library-only local project, go.mod can contain only a module
path and a go version line. Run go test ./... from that root to test its
packages. A go.sum file records dependency checksums when dependencies require
them; it is not a list of exported functions or a lock for your local API.
The sandbox deliberately disables module fetching and toolchain downloads.
Read the lab README for exact offline commands using the installed Go toolchain.
The build composes a public normalizer and a batch counter with fresh storage. Its bugs remove one normalization step or publish a partial map. Use the fill to state the ASCII alphabet clearly. Then read the public table tests and add one local counterexample before changing the implementation.