1// Copyright 2017 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package test
6
7import (
8	"cmd/go/internal/base"
9	"cmd/go/internal/cfg"
10	"fmt"
11	"io"
12	"os"
13	"path/filepath"
14	"sync"
15)
16
17var coverMerge struct {
18	f          *os.File
19	sync.Mutex // for f.Write
20}
21
22// initCoverProfile initializes the test coverage profile.
23// It must be run before any calls to mergeCoverProfile or closeCoverProfile.
24// Using this function clears the profile in case it existed from a previous run,
25// or in case it doesn't exist and the test is going to fail to create it (or not run).
26func initCoverProfile() {
27	if testCoverProfile == "" || testC {
28		return
29	}
30	if !filepath.IsAbs(testCoverProfile) {
31		testCoverProfile = filepath.Join(testOutputDir.getAbs(), testCoverProfile)
32	}
33
34	// No mutex - caller's responsibility to call with no racing goroutines.
35	f, err := os.Create(testCoverProfile)
36	if err != nil {
37		base.Fatalf("%v", err)
38	}
39	_, err = fmt.Fprintf(f, "mode: %s\n", cfg.BuildCoverMode)
40	if err != nil {
41		base.Fatalf("%v", err)
42	}
43	coverMerge.f = f
44}
45
46// mergeCoverProfile merges file into the profile stored in testCoverProfile.
47// It prints any errors it encounters to ew.
48func mergeCoverProfile(ew io.Writer, file string) {
49	if coverMerge.f == nil {
50		return
51	}
52	coverMerge.Lock()
53	defer coverMerge.Unlock()
54
55	expect := fmt.Sprintf("mode: %s\n", cfg.BuildCoverMode)
56	buf := make([]byte, len(expect))
57	r, err := os.Open(file)
58	if err != nil {
59		// Test did not create profile, which is OK.
60		return
61	}
62	defer r.Close()
63
64	n, err := io.ReadFull(r, buf)
65	if n == 0 {
66		return
67	}
68	if err != nil || string(buf) != expect {
69		fmt.Fprintf(ew, "error: test wrote malformed coverage profile %s.\n", file)
70		return
71	}
72	_, err = io.Copy(coverMerge.f, r)
73	if err != nil {
74		fmt.Fprintf(ew, "error: saving coverage profile: %v\n", err)
75	}
76}
77
78func closeCoverProfile() {
79	if coverMerge.f == nil {
80		return
81	}
82	if err := coverMerge.f.Close(); err != nil {
83		base.Errorf("closing coverage profile: %v", err)
84	}
85}
86