1// Copyright 2022 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 cmerge_test
6
7import (
8	"fmt"
9	"internal/coverage"
10	"internal/coverage/cmerge"
11	"testing"
12)
13
14func TestClash(t *testing.T) {
15	m := &cmerge.Merger{}
16	err := m.SetModeAndGranularity("mdf1.data", coverage.CtrModeSet, coverage.CtrGranularityPerBlock)
17	if err != nil {
18		t.Fatalf("unexpected clash: %v", err)
19	}
20	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeSet, coverage.CtrGranularityPerBlock)
21	if err != nil {
22		t.Fatalf("unexpected clash: %v", err)
23	}
24	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeCount, coverage.CtrGranularityPerBlock)
25	if err == nil {
26		t.Fatalf("expected mode clash, not found")
27	}
28	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeSet, coverage.CtrGranularityPerFunc)
29	if err == nil {
30		t.Fatalf("expected granularity clash, not found")
31	}
32	m.SetModeMergePolicy(cmerge.ModeMergeRelaxed)
33	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeCount, coverage.CtrGranularityPerBlock)
34	if err != nil {
35		t.Fatalf("unexpected clash: %v", err)
36	}
37	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeSet, coverage.CtrGranularityPerBlock)
38	if err != nil {
39		t.Fatalf("unexpected clash: %v", err)
40	}
41	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeAtomic, coverage.CtrGranularityPerBlock)
42	if err != nil {
43		t.Fatalf("unexpected clash: %v", err)
44	}
45	m.ResetModeAndGranularity()
46	err = m.SetModeAndGranularity("mdf1.data", coverage.CtrModeCount, coverage.CtrGranularityPerFunc)
47	if err != nil {
48		t.Fatalf("unexpected clash after reset: %v", err)
49	}
50}
51
52func TestBasic(t *testing.T) {
53	scenarios := []struct {
54		cmode         coverage.CounterMode
55		cgran         coverage.CounterGranularity
56		src, dst, res []uint32
57		iters         int
58		merr          bool
59		overflow      bool
60	}{
61		{
62			cmode:    coverage.CtrModeSet,
63			cgran:    coverage.CtrGranularityPerBlock,
64			src:      []uint32{1, 0, 1},
65			dst:      []uint32{1, 1, 0},
66			res:      []uint32{1, 1, 1},
67			iters:    2,
68			overflow: false,
69		},
70		{
71			cmode:    coverage.CtrModeCount,
72			cgran:    coverage.CtrGranularityPerBlock,
73			src:      []uint32{1, 0, 3},
74			dst:      []uint32{5, 7, 0},
75			res:      []uint32{6, 7, 3},
76			iters:    1,
77			overflow: false,
78		},
79		{
80			cmode:    coverage.CtrModeCount,
81			cgran:    coverage.CtrGranularityPerBlock,
82			src:      []uint32{4294967200, 0, 3},
83			dst:      []uint32{4294967001, 7, 0},
84			res:      []uint32{4294967295, 7, 3},
85			iters:    1,
86			overflow: true,
87		},
88	}
89
90	for k, scenario := range scenarios {
91		var err error
92		var ovf bool
93		m := &cmerge.Merger{}
94		mdf := fmt.Sprintf("file%d", k)
95		err = m.SetModeAndGranularity(mdf, scenario.cmode, scenario.cgran)
96		if err != nil {
97			t.Fatalf("case %d SetModeAndGranularity failed: %v", k, err)
98		}
99		for i := 0; i < scenario.iters; i++ {
100			err, ovf = m.MergeCounters(scenario.dst, scenario.src)
101			if ovf != scenario.overflow {
102				t.Fatalf("case %d overflow mismatch: got %v want %v", k, ovf, scenario.overflow)
103			}
104			if !scenario.merr && err != nil {
105				t.Fatalf("case %d unexpected err %v", k, err)
106			}
107			if scenario.merr && err == nil {
108				t.Fatalf("case %d expected err, not received", k)
109			}
110			for i := range scenario.dst {
111				if scenario.dst[i] != scenario.res[i] {
112					t.Fatalf("case %d: bad merge at %d got %d want %d",
113						k, i, scenario.dst[i], scenario.res[i])
114				}
115			}
116		}
117	}
118}
119