<commit_before>package expr

import (
	"math"
	"strconv"
	"testing"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/schema"
	"github.com/grafana/metrictank/test"
)

func TestOffsetToZero(t *testing.T) {
	const (
		positiveOffset = 10
		negativeOffset = -10
	)
	for _, tc := range []struct {
		name   string
		input  []models.Series
		output []models.Series
	}{
		{
			name:   "no input",
			input:  []models.Series{},
			output: []models.Series{},
		},
		{
			name: "single positive offset",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + positiveOffset, Ts: 10},
					{Val: 0 + positiveOffset, Ts: 20},
					{Val: 5.5 + positiveOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890 + positiveOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
		{
			name: "single negative offset",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + negativeOffset, Ts: 10},
					{Val: 0 + negativeOffset, Ts: 20},
					{Val: 5.5 + negativeOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890 + negativeOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
		{
			name: "negative infinity",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.Inf(-1), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: math.Inf(1), Ts: 10},
					{Val: math.Inf(1), Ts: 20},
					{Val: math.Inf(1), Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: math.Inf(1), Ts: 60},
				}),
			},
		},
		{
			name: "multiple",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + positiveOffset, Ts: 10},
					{Val: 0 + positiveOffset, Ts: 20},
					{Val: 5.5 + positiveOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890 + positiveOffset, Ts: 60},
				}),
				getSeriesNamed("b", []schema.Point{
					{Val: 0 + positiveOffset, Ts: 10},
					{Val: 0 + positiveOffset, Ts: 20},
					{Val: 5.5 + positiveOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890 + positiveOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
				getSeriesNamed("offsetToZero(b)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			f := NewOffsetToZero()
			f.(*FuncOffsetToZero).in = NewMock(tc.input)

			inputCopy := models.SeriesCopy(tc.input) // to later verify that it is unchanged

			dataMap := initDataMap(tc.input)

			got, err := f.Exec(dataMap)
			if err := equalOutput(tc.output, got, nil, err); err != nil {
				t.Fatalf("Case %s: %s", tc.name, err)
			}
<commit_msg>Use different numbers for series 'b'<commit_after>package expr

import (
	"math"
	"strconv"
	"testing"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/schema"
	"github.com/grafana/metrictank/test"
)

func TestOffsetToZero(t *testing.T) {
	const (
		positiveOffset = 10
		negativeOffset = -10
	)
	for _, tc := range []struct {
		name   string
		input  []models.Series
		output []models.Series
	}{
		{
			name:   "no input",
			input:  []models.Series{},
			output: []models.Series{},
		},
		{
			name: "single positive offset",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + positiveOffset, Ts: 10},
					{Val: 0 + positiveOffset, Ts: 20},
					{Val: 5.5 + positiveOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890 + positiveOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
		{
			name: "single negative offset",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + negativeOffset, Ts: 10},
					{Val: 0 + negativeOffset, Ts: 20},
					{Val: 5.5 + negativeOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890 + negativeOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
		{
			name: "negative infinity",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.Inf(-1), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: math.Inf(1), Ts: 10},
					{Val: math.Inf(1), Ts: 20},
					{Val: math.Inf(1), Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.Inf(1), Ts: 50},
					{Val: math.Inf(1), Ts: 60},
				}),
			},
		},
		{
			name: "multiple",
			input: []models.Series{
				getSeriesNamed("a", []schema.Point{
					{Val: 0 + positiveOffset, Ts: 10},
					{Val: 0 + positiveOffset, Ts: 20},
					{Val: 5.5 + positiveOffset, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890 + positiveOffset, Ts: 60},
				}),
				getSeriesNamed("b", []schema.Point{
					{Val: 0 + negativeOffset, Ts: 10},
					{Val: 42 + negativeOffset, Ts: 20},
					{Val: 288 + negativeOffset, Ts: 30},
					{Val: 1024 + negativeOffset, Ts: 40},
					{Val: 2048 + negativeOffset, Ts: 50},
					{Val: 1234567890 + negativeOffset, Ts: 60},
				}),
			},
			output: []models.Series{
				getSeriesNamed("offsetToZero(a)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 0, Ts: 20},
					{Val: 5.5, Ts: 30},
					{Val: math.NaN(), Ts: 40},
					{Val: math.NaN(), Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
				getSeriesNamed("offsetToZero(b)", []schema.Point{
					{Val: 0, Ts: 10},
					{Val: 42, Ts: 20},
					{Val: 288, Ts: 30},
					{Val: 1024, Ts: 40},
					{Val: 2048, Ts: 50},
					{Val: 1234567890, Ts: 60},
				}),
			},
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			f := NewOffsetToZero()
			f.(*FuncOffsetToZero).in = NewMock(tc.input)

			inputCopy := models.SeriesCopy(tc.input) // to later verify that it is unchanged

			dataMap := initDataMap(tc.input)

			got, err := f.Exec(dataMap)
			if err := equalOutput(tc.output, got, nil, err); err != nil {
				t.Fatalf("Case %s: %s", tc.name, err)
			}

{'fraction_non_alphanumeric': 0.20761335585292973, 'fraction_numerical': 0.07041704560218266, 'mean_word_length': 2.6379962192816637, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6862743', 'n_tokens_mistral': 4196, 'n_tokens_neox': 2983, 'n_words': 753}