maddy

git clone git://git.lin.moe/fmaddy/maddy.git

 1//go:build cover_main
 2// +build cover_main
 3
 4/*
 5Maddy Mail Server - Composable all-in-one email server.
 6Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
 7
 8This program is free software: you can redistribute it and/or modify
 9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program.  If not, see <https://www.gnu.org/licenses/>.
20*/
21
22package tests
23
24/*
25Go toolchain lacks the ability to instrument arbitrary executables with
26coverage counters.
27
28This file wraps the maddy executable into a minimal layer of "test" logic to
29make 'go test' work for it and produce the coverage report.
30
31Use ./build_cover.sh to compile it into ./maddy.cover.
32
33References:
34https://stackoverflow.com/questions/43381335/how-to-capture-code-coverage-from-a-go-binary
35https://blog.cloudflare.com/go-coverage-with-external-tests/
36https://github.com/albertito/chasquid/blob/master/coverage_test.go
37*/
38
39import (
40	"flag"
41	"io"
42	"os"
43	"testing"
44
45	_ "github.com/foxcpp/maddy"                  // To register run command
46	_ "github.com/foxcpp/maddy/internal/cli/ctl" // To register other CLI commands.
47
48	maddycli "github.com/foxcpp/maddy/internal/cli"
49)
50
51func TestMain(m *testing.M) {
52	// -test.* flags are registered somewhere in init() in "testing" (?).
53
54	// maddy.Run changes the working directory, we need to change it back so
55	// -test.coverprofile writes out profile in the right location.
56	wd, err := os.Getwd()
57	if err != nil {
58		panic(err)
59	}
60
61	// Skip flag parsing and make flag.Parse no-op so when
62	// m.Run calls it it will not error out on maddy flags.
63	args := os.Args
64	os.Args = []string{"command"}
65	flag.Parse()
66	os.Args = args
67
68	code := maddycli.RunWithoutExit()
69
70	if err := os.Chdir(wd); err != nil {
71		panic(err)
72	}
73
74	// Silence output produced by "testing" runtime.
75	r, w, err := os.Pipe()
76	if err == nil {
77		os.Stderr = w
78		os.Stdout = w
79	}
80	go func() {
81		_, _ = io.ReadAll(r)
82	}()
83
84	// Even though we do not have any tests to run, we need to call out into
85	// "testing" to make it process flags and produce the coverage report.
86	m.Run()
87
88	// TestMain doc says we have to exit with a sensible status code on our
89	// own.
90	os.Exit(code)
91}