1//go:build cover_main2// +build cover_main34/*5Maddy Mail Server - Composable all-in-one email server.6Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors78This program is free software: you can redistribute it and/or modify9it under the terms of the GNU General Public License as published by10the Free Software Foundation, either version 3 of the License, or11(at your option) any later version.1213This program is distributed in the hope that it will be useful,14but WITHOUT ANY WARRANTY; without even the implied warranty of15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16GNU General Public License for more details.1718You should have received a copy of the GNU General Public License19along with this program. If not, see <https://www.gnu.org/licenses/>.20*/2122package tests2324/*25Go toolchain lacks the ability to instrument arbitrary executables with26coverage counters.2728This file wraps the maddy executable into a minimal layer of "test" logic to29make 'go test' work for it and produce the coverage report.3031Use ./build_cover.sh to compile it into ./maddy.cover.3233References:34https://stackoverflow.com/questions/43381335/how-to-capture-code-coverage-from-a-go-binary35https://blog.cloudflare.com/go-coverage-with-external-tests/36https://github.com/albertito/chasquid/blob/master/coverage_test.go37*/3839import (40 "flag"41 "io"42 "os"43 "testing"4445 _ "github.com/foxcpp/maddy" // To register run command46 _ "github.com/foxcpp/maddy/internal/cli/ctl" // To register other CLI commands.4748 maddycli "github.com/foxcpp/maddy/internal/cli"49)5051func TestMain(m *testing.M) {52 // -test.* flags are registered somewhere in init() in "testing" (?).5354 // maddy.Run changes the working directory, we need to change it back so55 // -test.coverprofile writes out profile in the right location.56 wd, err := os.Getwd()57 if err != nil {58 panic(err)59 }6061 // Skip flag parsing and make flag.Parse no-op so when62 // m.Run calls it it will not error out on maddy flags.63 args := os.Args64 os.Args = []string{"command"}65 flag.Parse()66 os.Args = args6768 code := maddycli.RunWithoutExit()6970 if err := os.Chdir(wd); err != nil {71 panic(err)72 }7374 // Silence output produced by "testing" runtime.75 r, w, err := os.Pipe()76 if err == nil {77 os.Stderr = w78 os.Stdout = w79 }80 go func() {81 _, _ = io.ReadAll(r)82 }()8384 // Even though we do not have any tests to run, we need to call out into85 // "testing" to make it process flags and produce the coverage report.86 m.Run()8788 // TestMain doc says we have to exit with a sensible status code on our89 // own.90 os.Exit(code)91}