// Copyright 2017 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 app

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"strings"
	"testing"

	"golang.org/x/perf/storage"
	"golang.org/x/perf/storage/benchfmt"
)

func TestResultGroup(t *testing.T) {
	data := `key: value
BenchmarkName 1 ns/op
key: value2
BenchmarkName 1 ns/op`
	var results []*benchfmt.Result
	br := benchfmt.NewReader(strings.NewReader(data))
	g := &resultGroup{}
	for br.Next() {
		results = append(results, br.Result())
		g.add(br.Result())
	}
	if err := br.Err(); err != nil {
		t.Fatalf("Err() = %v, want nil", err)
	}
	if !reflect.DeepEqual(g.results, results) {
		t.Errorf("g.results = %#v, want %#v", g.results, results)
	}
	if want := map[string]valueSet{"key": {"value": 1, "value2": 1}}; !reflect.DeepEqual(g.LabelValues, want) {
		t.Errorf("g.LabelValues = %#v, want %#v", g.LabelValues, want)
	}
	groups := g.splitOn("key")
	if len(groups) != 2 {
		t.Fatalf("g.splitOn returned %d groups, want 2", len(groups))
	}
	for i, results := range [][]*benchfmt.Result{
		{results[0]},
		{results[1]},
	} {
		if !reflect.DeepEqual(groups[i].results, results) {
			t.Errorf("groups[%d].results = %#v, want %#v", i, groups[i].results, results)
		}
	}
}

// static responses for TestCompareQuery
var compareQueries = map[string]string{
	"one": `upload: 1
upload-part: 1
label: value
BenchmarkOne 1 5 ns/op
BenchmarkTwo 1 10 ns/op`,
	"two": `upload: 1
upload-part: 2
BenchmarkOne 1 10 ns/op
BenchmarkTwo 1 5 ns/op`,
	"onetwo": `upload: 1
upload-part: 1
label: value
BenchmarkOne 1 5 ns/op
BenchmarkTwo 1 10 ns/op
label:
upload-part: 2
BenchmarkOne 1 10 ns/op
BenchmarkTwo 1 5 ns/op`,
}

func TestCompareQuery(t *testing.T) {
	// TODO(quentin): This test seems too heavyweight; we are but shouldn't be also testing the storage client -> storage server interaction.
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if err := r.ParseForm(); err != nil {
			t.Errorf("ParseForm = %v", err)
		}
		q := r.Form.Get("q")
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		fmt.Fprint(w, compareQueries[q])
	}))
	defer ts.Close()

	a := &App{StorageClient: &storage.Client{BaseURL: ts.URL}}

	for _, q := range []string{"one vs two", "onetwo"} {
		t.Run(q, func(t *testing.T) {
			data := a.compareQuery(context.Background(), q)
			if data.Error != "" {
				t.Fatalf("compareQuery failed: %s", data.Error)
			}
			if have := data.Q; have != q {
				t.Errorf("Q = %q, want %q", have, q)
			}
			if len(data.Groups) != 2 {
				t.Errorf("len(Groups) = %d, want 2", len(data.Groups))
			}
			if len(data.Benchstat) == 0 {
				t.Error("len(Benchstat) = 0, want >0")
			}
			if want := map[string]bool{"upload-part": true, "label": true}; !reflect.DeepEqual(data.Labels, want) {
				t.Errorf("Labels = %#v, want %#v", data.Labels, want)
			}
			if want := (benchfmt.Labels{"upload": "1"}); !reflect.DeepEqual(data.CommonLabels, want) {
				t.Errorf("CommonLabels = %#v, want %#v", data.CommonLabels, want)
			}
		})
	}
}

func TestAddToQuery(t *testing.T) {
	tests := []struct {
		query, add string
		want       string
	}{
		{"one", "two", "two | one"},
		{"pre | one vs two", "three", "three pre | one vs two"},
		{"four", "five six", `"five six" | four`},
		{"seven", `extra "fun"\problem`, `"extra \"fun\"\\problem" | seven`},
		{"eight", `ni\"ne`, `"ni\\\"ne" | eight`},
	}
	for i, test := range tests {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			if got := addToQuery(test.query, test.add); got != test.want {
				t.Errorf("addToQuery(%q, %q) = %q, want %q", test.query, test.add, got, test.want)
			}
		})
	}
}

func TestElideKeyValues(t *testing.T) {
	type sb map[string]bool
	tests := []struct {
		content string
		keys    sb
		want    string
	}{
		{"BenchmarkOne/key=1-1 1 ns/op", sb{"key": true}, "BenchmarkOne/key=*-1 1 ns/op"},
		{"BenchmarkOne/key=1-2 1 ns/op", sb{"other": true}, "BenchmarkOne/key=1-2 1 ns/op"},
		{"BenchmarkOne/key=1/key2=2-3 1 ns/op", sb{"key": true}, "BenchmarkOne/key=*/key2=2-3 1 ns/op"},
		{"BenchmarkOne/foo/bar-4 1 ns/op", sb{"sub1": true}, "BenchmarkOne/*/bar-4 1 ns/op"},
		{"BenchmarkOne/foo/bar-5 1 ns/op", sb{"gomaxprocs": true}, "BenchmarkOne/foo/bar-* 1 ns/op"},
		{"BenchmarkOne/foo/bar-6 1 ns/op", sb{"name": true}, "Benchmark*/foo/bar-6 1 ns/op"},
	}
	for i, test := range tests {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			have := elideKeyValues(test.content, test.keys)
			if have != test.want {
				t.Errorf("elideKeys(%q, %#v) = %q, want %q", test.content, map[string]bool(test.keys), have, test.want)
			}
		})
	}
}
