bhylu.com

Advertisements

Go Testing

Compare a function’s result with independent expected values.

How it works

Go’s testing package discovers Test functions in files ending _test.go. Each receives *testing.T and reports a mismatch with Fatalf or Errorf. Table-driven tests keep boundary fixtures readable. The separate packages-lab includes a real parcel_test.go run by go test ./....

Run this Go example

Install Go separately from the official Go downloads and check go version in a new terminal. The reviewed baseline is Go 1.27.3 on Windows amd64; the authored syntax and standard-library APIs require Go 1.22 or newer. Save the complete source below as testing.go in a learning folder, then run go run testing.go from that folder. These examples use only the standard library.

Bhylu has no Go browser runner. Apache, MySQL, PHP and the JavaScript or Python playground are not required to run these files. File examples own a temporary directory; HTTP client examples create an ephemeral loopback server and close it. They do not contact an external API.

Download the complete testing.go · Download all source files with hash checks

For the optional collection download, save download-examples.mjs in a new learning folder and run node download-examples.mjs. A local preview uses node download-examples.mjs http://127.0.0.1:8000/examples/go/. The downloader refuses an existing bhylu-go-examples folder and installs or executes no Go code.

Example

testing.go

package main

import (
	"fmt"
)

func main() {
	cases := []struct{ capacity, used, want int }{{5, 0, 5}, {5, 5, 0}, {5, 2, 3}}
	for _, test := range cases {
		got := test.capacity - test.used
		if got != test.want {
			panic("fixture mismatch")
		}
	}
	fmt.Println("3 capacity fixtures passed")
}

Expected result

3 capacity fixtures passed

The standalone example demonstrates comparison without pretending to be a _test.go file. The real lab tests the exported checked helper and refused operations, rather than a duplicate implementation hidden in the test.

A real package and test lab

The source collection includes a separate module named bhylu.example/parcel-lab. After downloading the collection, run node setup-lab.mjs inside bhylu-go-examples. It copies only the included source files into a new parcel-lab folder and refuses an existing folder. Change to that folder and run go test ./..., go vet ./... and go run .. No third-party packages or network download are needed.

Run generated-input fuzzing with go test ./internal/locker -run=^$ -fuzz=FuzzParse -fuzztime=3s -parallel=2. Run a local benchmark with go test ./internal/locker -run=^$ -bench=. -benchmem. A short test or fuzz run is evidence for its executed fixtures, not proof of correctness. Race detection requires a supported Go/C toolchain; the ordinary native course review does not claim race-detector coverage.

packages-lab-go.mod

Download packages-lab-go.mod

packages-lab-go.mod

module bhylu.example/parcel-lab

go 1.22

packages-lab-main.go

Download packages-lab-main.go

packages-lab-main.go

package main

import (
	"bhylu.example/parcel-lab/internal/locker"
	"fmt"
)

func main() {
	desk := locker.Desk{Capacity: 5}
	for _, n := range []int{2, 0, 4, 3} {
		err := desk.Add(n)
		fmt.Println(err == nil, desk.Used)
	}
	fmt.Println("free", desk.Capacity-desk.Used)
}

packages-lab-locker.go

Download packages-lab-locker.go

packages-lab-locker.go

package locker

import (
	"fmt"
	"strconv"
	"strings"
	"sync"
)

type Desk struct{ Capacity, Used int }

func (d *Desk) Add(n int) error {
	if d == nil || d.Capacity < 0 || d.Used < 0 || d.Used > d.Capacity {
		return fmt.Errorf("invalid state")
	}
	if n <= 0 || n > d.Capacity-d.Used {
		return fmt.Errorf("request does not fit")
	}
	d.Used += n
	return nil
}
func ParseCount(raw string) (int, error) {
	raw = strings.TrimSpace(raw)
	if len(raw) == 0 || len(raw) > 3 {
		return 0, fmt.Errorf("count length")
	}
	for _, ch := range raw {
		if ch < '0' || ch > '9' {
			return 0, fmt.Errorf("digits only")
		}
	}
	n, err := strconv.Atoi(raw)
	if err != nil || n > 100 {
		return 0, fmt.Errorf("count range")
	}
	return n, nil
}

type SafeDesk struct {
	mu   sync.Mutex
	desk Desk
}

func NewSafeDesk(capacity int) (*SafeDesk, error) {
	if capacity < 0 {
		return nil, fmt.Errorf("invalid capacity")
	}
	return &SafeDesk{desk: Desk{Capacity: capacity}}, nil
}
func (d *SafeDesk) Add(n int) error { d.mu.Lock(); defer d.mu.Unlock(); return d.desk.Add(n) }
func (d *SafeDesk) Used() int       { d.mu.Lock(); defer d.mu.Unlock(); return d.desk.Used }

packages-lab-locker_test.go

Download packages-lab-locker_test.go

packages-lab-locker_test.go

package locker

import (
	"strings"
	"sync"
	"testing"
)

func TestAddBoundaries(t *testing.T) {
	max := int(^uint(0) >> 1)
	cases := []struct {
		cap, used, n, want int
		ok                 bool
	}{{5, 0, 2, 2, true}, {5, 2, 0, 2, false}, {5, 2, -1, 2, false}, {5, 2, 4, 2, false}, {5, 2, 3, 5, true}, {0, 0, 1, 0, false}, {-1, 0, 1, 0, false}, {5, 6, 1, 6, false}, {5, -1, 1, -1, false}, {max, max - 1, 2, max - 1, false}, {max, max - 1, 1, max, true}}
	for _, c := range cases {
		d := Desk{c.cap, c.used}
		err := d.Add(c.n)
		if (err == nil) != c.ok || d.Used != c.want {
			t.Fatalf("fixture %+v: used=%d err=%v", c, d.Used, err)
		}
	}
	var absent *Desk
	if absent.Add(1) == nil {
		t.Fatal("nil accepted")
	}
}
func TestSequenceModel(t *testing.T) {
	for capacity := 0; capacity < 12; capacity++ {
		d := Desk{Capacity: capacity}
		want := 0
		for _, n := range []int{1, 2, -1, 0, 4, 1, 9, 1} {
			ok := n > 0 && n <= capacity-want
			if ok {
				want += n
			}
			err := d.Add(n)
			if (err == nil) != ok || d.Used != want {
				t.Fatalf("capacity=%d n=%d used=%d want=%d", capacity, n, d.Used, want)
			}
		}
	}
}
func TestParseCount(t *testing.T) {
	for _, c := range []struct {
		raw  string
		want int
		ok   bool
	}{{"0", 0, true}, {" 17 ", 17, true}, {"100", 100, true}, {"101", 0, false}, {"-1", 0, false}, {"2.5", 0, false}, {"", 0, false}, {"1x", 0, false}, {"999999999999999999", 0, false}, {"1", 0, false}} {
		got, err := ParseCount(c.raw)
		if (err == nil) != c.ok || got != c.want {
			t.Fatalf("%q got=%d err=%v", c.raw, got, err)
		}
	}
}
func TestConcurrentLimit(t *testing.T) {
	for round := 0; round < 20; round++ {
		d, err := NewSafeDesk(7)
		if err != nil {
			t.Fatal(err)
		}
		var wg sync.WaitGroup
		out := make(chan bool, 40)
		for i := 0; i < 40; i++ {
			wg.Add(1)
			go func() { defer wg.Done(); out <- d.Add(1) == nil }()
		}
		wg.Wait()
		close(out)
		accepted := 0
		for ok := range out {
			if ok {
				accepted++
			}
		}
		if accepted != 7 || d.Used() != 7 {
			t.Fatalf("accepted=%d used=%d", accepted, d.Used())
		}
	}
	if _, err := NewSafeDesk(-1); err == nil {
		t.Fatal("negative capacity accepted")
	}
}
func FuzzParse(f *testing.F) {
	for _, seed := range []string{"0", "17", "-1", "bad", "101", ""} {
		f.Add(seed)
	}
	f.Fuzz(func(t *testing.T, raw string) {
		got, err := ParseCount(raw)
		if err != nil {
			return
		}
		if got < 0 || got > 100 {
			t.Fatalf("outside range: %d", got)
		}
		trimmed := strings.TrimSpace(raw)
		if len(trimmed) < 1 || len(trimmed) > 3 {
			t.Fatal("length")
		}
		want := 0
		for _, b := range []byte(trimmed) {
			if b < '0' || b > '9' {
				t.Fatal("non-digit")
			}
			want = want*10 + int(b-'0')
		}
		if got != want {
			t.Fatalf("got=%d want=%d", got, want)
		}
	})
}

var benchmarkText string

func BenchmarkJoin(b *testing.B) {
	names := []string{"P-81", "P-82", "P-83"}
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		benchmarkText = strings.Join(names, ",")
	}
}

For language rules and APIs, use the Go language specification and standard-library documentation. The fictional examples are learning fixtures, not a deployed parcel service.

Advertisements