// Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package metrics_test import ( "bufio" "os" "regexp" "runtime/metrics" "strings" "testing" ) func TestDescriptionNameFormat(t *testing.T) { r := regexp.MustCompile("^(?P/[^:]+):(?P[^:*/]+(?:[*/][^:*/]+)*)$") descriptions := metrics.All() for _, desc := range descriptions { if !r.MatchString(desc.Name) { t.Errorf("metrics %q does not match regexp %s", desc.Name, r) } } } func extractMetricDocs(t *testing.T) map[string]string { f, err := os.Open("doc.go") if err != nil { t.Fatalf("failed to open doc.go in runtime/metrics package: %v", err) } const ( stateSearch = iota // look for list of metrics stateNextMetric // look for next metric stateNextDescription // build description ) state := stateSearch s := bufio.NewScanner(f) result := make(map[string]string) var metric string var prevMetric string var desc strings.Builder for s.Scan() { line := strings.TrimSpace(s.Text()) switch state { case stateSearch: if line == "Below is the full list of supported metrics, ordered lexicographically." { state = stateNextMetric } case stateNextMetric: // Ignore empty lines until we find a non-empty // one. This will be our metric name. if len(line) != 0 { prevMetric = metric metric = line if prevMetric > metric { t.Errorf("metrics %s and %s are out of lexicographical order", prevMetric, metric) } state = stateNextDescription } case stateNextDescription: if len(line) == 0 || line == `*/` { // An empty line means we're done. // Write down the description and look // for a new metric. result[metric] = desc.String() desc.Reset() state = stateNextMetric } else { // As long as we're seeing data, assume that's // part of the description and append it. if desc.Len() != 0 { // Turn previous newlines into spaces. desc.WriteString(" ") } desc.WriteString(line) } } if line == `*/` { break } } if state == stateSearch { t.Fatalf("failed to find supported metrics docs in %s", f.Name()) } return result } func TestDescriptionDocs(t *testing.T) { docs := extractMetricDocs(t) descriptions := metrics.All() for _, d := range descriptions { want := d.Description got, ok := docs[d.Name] if !ok { t.Errorf("no docs found for metric %s", d.Name) continue } if got != want { t.Errorf("mismatched description and docs for metric %s", d.Name) t.Errorf("want: %q, got %q", want, got) continue } } if len(docs) > len(descriptions) { docsLoop: for name := range docs { for _, d := range descriptions { if name == d.Name { continue docsLoop } } t.Errorf("stale documentation for non-existent metric: %s", name) } } }