package prometheus

import (
	"bytes"
	"fmt"
	"math"
	"os"
	"testing"

	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/model/labels"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/netdata/netdata/go/plugins/pkg/prometheus/selector"
)

var (
	dataMultilineHelp, _ = os.ReadFile("testdata/multiline-help.txt")

	dataGaugeMeta, _       = os.ReadFile("testdata/gauge-meta.txt")
	dataGaugeNoMeta, _     = os.ReadFile("testdata/gauge-no-meta.txt")
	dataCounterMeta, _     = os.ReadFile("testdata/counter-meta.txt")
	dataCounterNoMeta, _   = os.ReadFile("testdata/counter-no-meta.txt")
	dataSummaryMeta, _     = os.ReadFile("testdata/summary-meta.txt")
	dataSummaryNoMeta, _   = os.ReadFile("testdata/summary-no-meta.txt")
	dataHistogramMeta, _   = os.ReadFile("testdata/histogram-meta.txt")
	dataHistogramNoMeta, _ = os.ReadFile("testdata/histogram-no-meta.txt")
	dataAllTypes           = joinData(
		dataGaugeMeta, dataGaugeNoMeta, dataCounterMeta, dataCounterNoMeta,
		dataSummaryMeta, dataSummaryNoMeta, dataHistogramMeta, dataHistogramNoMeta,
	)
)

func Test_testParseDataIsValid(t *testing.T) {
	for name, data := range map[string][]byte{
		"dataMultilineHelp":   dataMultilineHelp,
		"dataGaugeMeta":       dataGaugeMeta,
		"dataGaugeNoMeta":     dataGaugeNoMeta,
		"dataCounterMeta":     dataCounterMeta,
		"dataCounterNoMeta":   dataCounterNoMeta,
		"dataSummaryMeta":     dataSummaryMeta,
		"dataSummaryNoMeta":   dataSummaryNoMeta,
		"dataHistogramMeta":   dataHistogramMeta,
		"dataHistogramNoMeta": dataHistogramNoMeta,
		"dataAllTypes":        dataAllTypes,
	} {
		require.NotNilf(t, data, name)
	}
}

func TestPromTextParser_parseToMetricFamilies(t *testing.T) {
	tests := map[string]struct {
		input []byte
		want  MetricFamilies
	}{
		"Gauge with multiline HELP": {
			input: dataMultilineHelp,
			want: MetricFamilies{
				"test_gauge_metric_1": {
					name: "test_gauge_metric_1",
					help: "First line. Second line.",
					typ:  model.MetricTypeGauge,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							gauge:  &Gauge{value: 11},
						},
					},
				},
			},
		},
		"Gauge with meta parsed as Gauge": {
			input: dataGaugeMeta,
			want: MetricFamilies{
				"test_gauge_metric_1": {
					name: "test_gauge_metric_1",
					help: "Test Gauge Metric 1",
					typ:  model.MetricTypeGauge,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							gauge:  &Gauge{value: 11},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							gauge:  &Gauge{value: 12},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							gauge:  &Gauge{value: 13},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							gauge:  &Gauge{value: 14},
						},
					},
				},
				"test_gauge_metric_2": {
					name: "test_gauge_metric_2",
					typ:  model.MetricTypeGauge,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							gauge:  &Gauge{value: 11},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							gauge:  &Gauge{value: 12},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							gauge:  &Gauge{value: 13},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							gauge:  &Gauge{value: 14},
						},
					},
				},
			},
		},
		"Counter with meta parsed as Counter": {
			input: dataCounterMeta,
			want: MetricFamilies{
				"test_counter_metric_1_total": {
					name: "test_counter_metric_1_total",
					help: "Test Counter Metric 1",
					typ:  model.MetricTypeCounter,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							counter: &Counter{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							counter: &Counter{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							counter: &Counter{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							counter: &Counter{value: 14},
						},
					},
				},
				"test_counter_metric_2_total": {
					name: "test_counter_metric_2_total",
					typ:  model.MetricTypeCounter,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							counter: &Counter{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							counter: &Counter{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							counter: &Counter{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							counter: &Counter{value: 14},
						},
					},
				},
			},
		},
		"Summary with meta parsed as Summary": {
			input: dataSummaryMeta,
			want: MetricFamilies{
				"test_summary_1_duration_microseconds": {
					name: "test_summary_1_duration_microseconds",
					help: "Test Summary Metric 1",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
					},
				},
				"test_summary_2_duration_microseconds": {
					name: "test_summary_2_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
					},
				},
			},
		},
		"Histogram with meta parsed as Histogram": {
			input: dataHistogramMeta,
			want: MetricFamilies{
				"test_histogram_1_duration_seconds": {
					name: "test_histogram_1_duration_seconds",
					help: "Test Histogram Metric 1",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
					},
				},
				"test_histogram_2_duration_seconds": {
					name: "test_histogram_2_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
					},
				},
			},
		},
		"Gauge no meta parsed as Untyped": {
			input: dataGaugeNoMeta,
			want: MetricFamilies{
				"test_gauge_no_meta_metric_1": {
					name: "test_gauge_no_meta_metric_1",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_gauge_no_meta_metric_2": {
					name: "test_gauge_no_meta_metric_2",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
			},
		},
		"Counter no meta parsed as Untyped": {
			input: dataCounterNoMeta,
			want: MetricFamilies{
				"test_counter_no_meta_metric_1_total": {
					name: "test_counter_no_meta_metric_1_total",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_counter_no_meta_metric_2_total": {
					name: "test_counter_no_meta_metric_2_total",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
			},
		},
		"Summary no meta parsed as Summary": {
			input: dataSummaryNoMeta,
			want: MetricFamilies{
				"test_summary_no_meta_1_duration_microseconds": {
					name: "test_summary_no_meta_1_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
					},
				},
				"test_summary_no_meta_2_duration_microseconds": {
					name: "test_summary_no_meta_2_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
					},
				},
			},
		},
		"Histogram no meta parsed as Histogram": {
			input: dataHistogramNoMeta,
			want: MetricFamilies{
				"test_histogram_no_meta_1_duration_seconds": {
					name: "test_histogram_no_meta_1_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
					},
				},
				"test_histogram_no_meta_2_duration_seconds": {
					name: "test_histogram_no_meta_2_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
					},
				},
			},
		},
		"All types": {
			input: dataAllTypes,
			want: MetricFamilies{
				"test_gauge_metric_1": {
					name: "test_gauge_metric_1",
					help: "Test Gauge Metric 1",
					typ:  model.MetricTypeGauge,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							gauge:  &Gauge{value: 11},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							gauge:  &Gauge{value: 12},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							gauge:  &Gauge{value: 13},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							gauge:  &Gauge{value: 14},
						},
					},
				},
				"test_gauge_metric_2": {
					name: "test_gauge_metric_2",
					typ:  model.MetricTypeGauge,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							gauge:  &Gauge{value: 11},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							gauge:  &Gauge{value: 12},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							gauge:  &Gauge{value: 13},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							gauge:  &Gauge{value: 14},
						},
					},
				},
				"test_counter_metric_1_total": {
					name: "test_counter_metric_1_total",
					help: "Test Counter Metric 1",
					typ:  model.MetricTypeCounter,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							counter: &Counter{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							counter: &Counter{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							counter: &Counter{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							counter: &Counter{value: 14},
						},
					},
				},
				"test_counter_metric_2_total": {
					name: "test_counter_metric_2_total",
					typ:  model.MetricTypeCounter,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							counter: &Counter{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							counter: &Counter{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							counter: &Counter{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							counter: &Counter{value: 14},
						},
					},
				},
				"test_summary_1_duration_microseconds": {
					name: "test_summary_1_duration_microseconds",
					help: "Test Summary Metric 1",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
					},
				},
				"test_summary_2_duration_microseconds": {
					name: "test_summary_2_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
					},
				},
				"test_histogram_1_duration_seconds": {
					name: "test_histogram_1_duration_seconds",
					help: "Test Histogram Metric 1",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
					},
				},
				"test_histogram_2_duration_seconds": {
					name: "test_histogram_2_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
					},
				},
				"test_gauge_no_meta_metric_1": {
					name: "test_gauge_no_meta_metric_1",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_gauge_no_meta_metric_2": {
					name: "test_gauge_no_meta_metric_2",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_counter_no_meta_metric_1_total": {
					name: "test_counter_no_meta_metric_1_total",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_counter_no_meta_metric_2_total": {
					name: "test_counter_no_meta_metric_2_total",
					typ:  model.MetricTypeUnknown,
					metrics: []Metric{
						{
							labels:  labels.Labels{{Name: "label1", Value: "value1"}},
							untyped: &Untyped{value: 11},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value2"}},
							untyped: &Untyped{value: 12},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value3"}},
							untyped: &Untyped{value: 13},
						},
						{
							labels:  labels.Labels{{Name: "label1", Value: "value4"}},
							untyped: &Untyped{value: 14},
						},
					},
				},
				"test_summary_no_meta_1_duration_microseconds": {
					name: "test_summary_no_meta_1_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   283201.29,
								count: 31,
								quantiles: []Quantile{
									{quantile: 0.5, value: 4931.921},
									{quantile: 0.9, value: 4932.921},
									{quantile: 0.99, value: 4933.921},
								},
							},
						},
					},
				},
				"test_summary_no_meta_2_duration_microseconds": {
					name: "test_summary_no_meta_2_duration_microseconds",
					typ:  model.MetricTypeSummary,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							summary: &Summary{
								sum:   383201.29,
								count: 41,
								quantiles: []Quantile{
									{quantile: 0.5, value: 5931.921},
									{quantile: 0.9, value: 5932.921},
									{quantile: 0.99, value: 5933.921},
								},
							},
						},
					},
				},
				"test_histogram_no_meta_1_duration_seconds": {
					name: "test_histogram_no_meta_1_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00147889,
								count: 6,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 4},
									{upperBound: 0.5, cumulativeCount: 5},
									{upperBound: math.Inf(1), cumulativeCount: 6},
								},
							},
						},
					},
				},
				"test_histogram_no_meta_2_duration_seconds": {
					name: "test_histogram_no_meta_2_duration_seconds",
					typ:  model.MetricTypeHistogram,
					metrics: []Metric{
						{
							labels: labels.Labels{{Name: "label1", Value: "value1"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value2"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value3"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
						{
							labels: labels.Labels{{Name: "label1", Value: "value4"}},
							histogram: &Histogram{
								sum:   0.00247889,
								count: 9,
								buckets: []Bucket{
									{upperBound: 0.1, cumulativeCount: 7},
									{upperBound: 0.5, cumulativeCount: 8},
									{upperBound: math.Inf(1), cumulativeCount: 9},
								},
							},
						},
					},
				},
			},
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			var p promTextParser

			for i := range 10 {
				t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) {
					mfs, err := p.parseToMetricFamilies(test.input)
					if len(test.want) > 0 {
						assert.Equal(t, test.want, mfs)
					} else {
						assert.Error(t, err)
					}
				})
			}
		})
	}
}

func TestPromTextParser_parseToMetricFamiliesWithSelector(t *testing.T) {
	sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`)
	require.NoError(t, err)

	p := promTextParser{sr: sr}

	txt := []byte(`
test_gauge_metric_1{label1="value1"} 1
test_gauge_metric_1{label1="value2"} 1
test_gauge_metric_2{label1="value1"} 1
test_gauge_metric_2{label1="value2"} 1
`)

	want := MetricFamilies{
		"test_gauge_metric_1": &MetricFamily{
			name: "test_gauge_metric_1",
			typ:  model.MetricTypeUnknown,
			metrics: []Metric{
				{labels: labels.Labels{{Name: "label1", Value: "value2"}}, untyped: &Untyped{value: 1}},
			},
		},
	}

	mfs, err := p.parseToMetricFamilies(txt)

	require.NoError(t, err)
	assert.Equal(t, want, mfs)
}

func TestPromTextParser_parseToSeries(t *testing.T) {
	tests := map[string]struct {
		input []byte
		want  Series
	}{
		"All types": {
			input: []byte(`
# HELP test_gauge_metric_1 Test Gauge Metric 1
# TYPE test_gauge_metric_1 gauge
test_gauge_metric_1{label1="value1"} 11
test_gauge_no_meta_metric_1{label1="value1"} 11
# HELP test_counter_metric_1_total Test Counter Metric 1
# TYPE test_counter_metric_1_total counter
test_counter_metric_1_total{label1="value1"} 11
test_counter_no_meta_metric_1_total{label1="value1"} 11
# HELP test_summary_1_duration_microseconds Test Summary Metric 1
# TYPE test_summary_1_duration_microseconds summary
test_summary_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
test_summary_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
test_summary_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
test_summary_1_duration_microseconds_sum{label1="value1"} 283201.29
test_summary_1_duration_microseconds_count{label1="value1"} 31
test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.5"} 4931.921
test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.9"} 4932.921
test_summary_no_meta_1_duration_microseconds{label1="value1",quantile="0.99"} 4933.921
test_summary_no_meta_1_duration_microseconds_sum{label1="value1"} 283201.29
test_summary_no_meta_1_duration_microseconds_count{label1="value1"} 31
# HELP test_histogram_1_duration_seconds Test Histogram Metric 1
# TYPE test_histogram_1_duration_seconds histogram
test_histogram_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
test_histogram_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
test_histogram_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
test_histogram_1_duration_seconds_sum{label1="value1"} 0.00147889
test_histogram_1_duration_seconds_count{label1="value1"} 6
test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.1"} 4
test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="0.5"} 5
test_histogram_no_meta_1_duration_seconds_bucket{label1="value1",le="+Inf"} 6
test_histogram_no_meta_1_duration_seconds_sum{label1="value1"} 0.00147889
test_histogram_no_meta_1_duration_seconds_count{label1="value1"} 6
`),
			want: Series{
				// Gauge
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_gauge_metric_1"},
						{Name: "label1", Value: "value1"},
					},
					Value: 11,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_gauge_no_meta_metric_1"},
						{Name: "label1", Value: "value1"},
					},
					Value: 11,
				},
				// Counter
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_counter_metric_1_total"},
						{Name: "label1", Value: "value1"},
					},
					Value: 11,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_counter_no_meta_metric_1_total"},
						{Name: "label1", Value: "value1"},
					},
					Value: 11,
				},
				//// Summary
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.5"},
					},
					Value: 4931.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.9"},
					},
					Value: 4932.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.99"},
					},
					Value: 4933.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_1_duration_microseconds_sum"},
						{Name: "label1", Value: "value1"},
					},
					Value: 283201.29,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_1_duration_microseconds_count"},
						{Name: "label1", Value: "value1"},
					},
					Value: 31,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.5"},
					},
					Value: 4931.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.9"},
					},
					Value: 4932.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds"},
						{Name: "label1", Value: "value1"},
						{Name: "quantile", Value: "0.99"},
					},
					Value: 4933.921,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_sum"},
						{Name: "label1", Value: "value1"},
					},
					Value: 283201.29,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_summary_no_meta_1_duration_microseconds_count"},
						{Name: "label1", Value: "value1"},
					},
					Value: 31,
				},
				// Histogram
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "0.1"},
					},
					Value: 4,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "0.5"},
					},
					Value: 5,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "+Inf"},
					},
					Value: 6,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_1_duration_seconds_sum"},
						{Name: "label1", Value: "value1"},
					},
					Value: 0.00147889,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_1_duration_seconds_count"},
						{Name: "label1", Value: "value1"},
					},
					Value: 6,
				},

				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "0.1"},
					},
					Value: 4,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "0.5"},
					},
					Value: 5,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_bucket"},
						{Name: "label1", Value: "value1"},
						{Name: "le", Value: "+Inf"},
					},
					Value: 6,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_sum"},
						{Name: "label1", Value: "value1"},
					},
					Value: 0.00147889,
				},
				{
					Labels: labels.Labels{
						{Name: "__name__", Value: "test_histogram_no_meta_1_duration_seconds_count"},
						{Name: "label1", Value: "value1"},
					},
					Value: 6,
				},
			},
		},
	}

	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			var p promTextParser

			for i := range 10 {
				t.Run(fmt.Sprintf("parse num %d", i+1), func(t *testing.T) {
					series, err := p.parseToSeries(test.input)

					if len(test.want) > 0 {
						test.want.Sort()
						assert.Equal(t, test.want, series)
					} else {
						assert.Error(t, err)
					}
				})
			}
		})
	}
}

func TestPromTextParser_parseToSeriesWithSelector(t *testing.T) {
	sr, err := selector.Parse(`test_gauge_metric_1{label1="value2"}`)
	require.NoError(t, err)

	p := promTextParser{sr: sr}

	txt := []byte(`
test_gauge_metric_1{label1="value1"} 1
test_gauge_metric_1{label1="value2"} 1
test_gauge_metric_2{label1="value1"} 1
test_gauge_metric_2{label1="value2"} 1
`)

	want := Series{SeriesSample{
		Labels: labels.Labels{
			{Name: "__name__", Value: "test_gauge_metric_1"},
			{Name: "label1", Value: "value2"},
		},
		Value: 1,
	}}

	series, err := p.parseToSeries(txt)

	require.NoError(t, err)
	assert.Equal(t, want, series)
}

func TestPromTextParser_parseToMetricFamilies_metricNameNotFirstLabel(t *testing.T) {
	var p promTextParser

	txt := []byte(`
# HELP DCGM_FI_DEV_GPU_UTIL GPU utilization
# TYPE DCGM_FI_DEV_GPU_UTIL gauge
DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
`)

	mfs, err := p.parseToMetricFamilies(txt)
	require.NoError(t, err)

	require.Contains(t, mfs, "DCGM_FI_DEV_GPU_UTIL")
	require.NotContains(t, mfs, "GPU-aaa")

	mf := mfs["DCGM_FI_DEV_GPU_UTIL"]
	require.Len(t, mf.metrics, 1)
	assert.Equal(t, model.MetricTypeGauge, mf.typ)
	assert.Equal(t, 80.0, mf.metrics[0].gauge.value)
	assert.EqualValues(t, labels.Labels{
		{Name: "UUID", Value: "GPU-aaa"},
		{Name: "gpu", Value: "0"},
	}, mf.metrics[0].labels)
}

func TestPromTextParser_parseToMetricFamilies_failsOnInvalidSeriesValue(t *testing.T) {
	var p promTextParser

	txt := []byte(`
# HELP DCGM_FI_DEV_GPU_UTIL GPU utilization
# TYPE DCGM_FI_DEV_GPU_UTIL gauge
DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
# HELP DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK Requested power profile mask
# TYPE DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK gauge
DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK{UUID="GPU-aaa",gpu="0"} ERROR - FAILED TO CONVERT TO STRING
`)

	_, err := p.parseToMetricFamilies(txt)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "failed to parse prometheus metrics")
}

func TestPromTextParser_parseToSeries_failsOnInvalidSeriesValue(t *testing.T) {
	var p promTextParser

	txt := []byte(`
DCGM_FI_DEV_GPU_UTIL{UUID="GPU-aaa",gpu="0"} 80
DCGM_FI_DEV_REQUESTED_POWER_PROFILE_MASK{UUID="GPU-aaa",gpu="0"} ERROR - FAILED TO CONVERT TO STRING
`)

	_, err := p.parseToSeries(txt)
	require.Error(t, err)
	assert.Contains(t, err.Error(), "failed to parse prometheus metrics")
}

func joinData(data ...[]byte) []byte {
	var buf bytes.Buffer
	for _, v := range data {
		_, _ = buf.Write(v)
		_ = buf.WriteByte('\n')
	}
	return buf.Bytes()
}
