<commit_before>package store

import (
	"junta/assert"
	"bytes"
	"gob"
	"strconv"
	"testing"
)

var SetKVCMs = [][]string{
	{"/", "a", Clobber, ":/=a"},
	{"/x", "a", Clobber, ":/x=a"},
	{"/x", "a=b", Clobber, ":/x=a=b"},
	{"/x", "a b", Clobber, ":/x=a b"},
	{"/", "a", Missing, "0:/=a"},
	{"/", "a", "123", "123:/=a"},
}

var DelKCMs = [][]string{
	{"/", Clobber, ":/"},
	{"/x", Clobber, ":/x"},
	{"/", Missing, "0:/"},
	{"/", "123", "123:/"},
}

var GoodPaths = []string{
	"/",
	"/x",
	"/x/y",
	"/x/y-z",
	"/x/y.z",
	"/x/0",
}

var BadPaths = []string{
	"",
	"x",
	"/x=",
	"/x y",
	"/x/",
	"/x//y",
}

var BadInstructions = []string{
	":",
	":x",
	":/x y",
	":=",
	":x=",
	":/x y=",
}

// Anything without a colon is a bad mutation because
// it is missing cas.
var BadMutations = []string{
	"",
	"x",
}

var Splits = [][]string{
	{"/"},
	{"/x", "x"},
	{"/x/y/z", "x", "y", "z"},
}

func clearGetter(ev Event) Event {
	ev.Getter = nil
	return ev
}

func TestSplit(t *testing.T) {
	for _, vals := range Splits {
		path, exp := vals[0], vals[1:]
		got := split(path)
		assert.Equal(t, exp, got, path)
	}
}

func TestCheckBadPaths(t *testing.T) {
	for _, k := range BadPaths {
		err := checkPath(k)
		_, ok := err.(*BadPathError)
		assert.Tf(t, ok, "for path %q, got %T: %v", k, err, err)
	}
}

func TestCheckGoodPaths(t *testing.T) {
	for _, k := range GoodPaths {
		err := checkPath(k)
		assert.Equalf(t, nil, err, "for path %q", k)
	}
}

func TestEncodeSet(t *testing.T) {
	for _, kvcm := range SetKVCMs {
		k, v, c, exp := kvcm[0], kvcm[1], kvcm[2], kvcm[3]
		got, err := EncodeSet(k, v, c)
		assert.Equal(t, nil, err)
		assert.Equal(t, exp, got)
	}
}

func TestEncodeDel(t *testing.T) {
	for _, kcm := range DelKCMs {
		k, c, exp := kcm[0], kcm[1], kcm[2]
		got, err := EncodeDel(k, c)
		assert.Equal(t, nil, err)
		assert.Equal(t, exp, got)
	}
}

func TestDecodeSet(t *testing.T) {
	for _, kvcm := range SetKVCMs {
		expk, expv, expc, m := kvcm[0], kvcm[1], kvcm[2], kvcm[3]
		gotk, gotv, gotc, keep, err := decode(m)
		assert.Equal(t, nil, err)
		assert.Equal(t, true, keep, "keep from "+m)
		assert.Equal(t, expk, gotk, "key from "+m)
		assert.Equal(t, expv, gotv, "value from "+m)
		assert.Equal(t, expc, gotc, "cas from "+m)
	}
}

func TestDecodeDel(t *testing.T) {
	for _, kcm := range DelKCMs {
		expk, expc, m := kcm[0], kcm[1], kcm[2]
		gotk, gotv, gotc, keep, err := decode(m)
		assert.Equal(t, nil, err)
		assert.Equal(t, false, keep, "keep from "+m)
		assert.Equal(t, expk, gotk, "key from "+m)
		assert.Equal(t, "", gotv, "value from "+m)
		assert.Equal(t, expc, gotc, "cas from "+m)
	}
}

func TestDecodeBadInstructions(t *testing.T) {
	for _, m := range BadInstructions {
		_, _, _, _, err := decode(m)
		_, ok := err.(*BadPathError)
		assert.Tf(t, ok, "for mut %q, got %T: %v", m, err, err)
	}
}

func TestDecodeBadMutations(t *testing.T) {
	for _, m := range BadMutations {
		_, _, _, _, err := decode(m)
		assert.Equal(t, ErrBadMutation, err)
	}
}

func TestGetMissing(t *testing.T) {
	s := New()
	v, cas := s.Get("/x")
	assert.Equal(t, Missing, cas)
	assert.Equal(t, []string{""}, v)
}

func TestGet(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Sync(1)
	v, cas := s.Get("/x")
	assert.Equal(t, "1", cas)
	assert.Equal(t, []string{"a"}, v)
}

func TestGetDeleted(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Apply(2, MustEncodeDel("/x", Clobber))
	s.Sync(2)
	v, cas := s.Get("/x")
	assert.Equal(t, Missing, cas)
	assert.Equal(t, []string{""}, v)
}

func TestApplyInOrder(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Apply(2, MustEncodeSet("/x", "b", Clobber))
	s.Sync(2)
	v, cas := s.Get("/x")
	assert.Equal(t, "2", cas)
	assert.Equal(t, []string{"b"}, v)
}

func TestGetSync(t *testing.T) {
	chV := make(chan []string)
	chCas := make(chan string)
	s := New()
	go func() {
		s.Sync(5)
		v, cas := s.Get("/x")
		chV <- v
		chCas <- cas<commit_msg>add some store benchmarks<commit_after>package store

import (
	"junta/assert"
	"bytes"
	"gob"
	"strconv"
	"testing"
)

var SetKVCMs = [][]string{
	{"/", "a", Clobber, ":/=a"},
	{"/x", "a", Clobber, ":/x=a"},
	{"/x", "a=b", Clobber, ":/x=a=b"},
	{"/x", "a b", Clobber, ":/x=a b"},
	{"/", "a", Missing, "0:/=a"},
	{"/", "a", "123", "123:/=a"},
}

var DelKCMs = [][]string{
	{"/", Clobber, ":/"},
	{"/x", Clobber, ":/x"},
	{"/", Missing, "0:/"},
	{"/", "123", "123:/"},
}

var GoodPaths = []string{
	"/",
	"/x",
	"/x/y",
	"/x/y-z",
	"/x/y.z",
	"/x/0",
}

var BadPaths = []string{
	"",
	"x",
	"/x=",
	"/x y",
	"/x/",
	"/x//y",
}

var BadInstructions = []string{
	":",
	":x",
	":/x y",
	":=",
	":x=",
	":/x y=",
}

// Anything without a colon is a bad mutation because
// it is missing cas.
var BadMutations = []string{
	"",
	"x",
}

var Splits = [][]string{
	{"/"},
	{"/x", "x"},
	{"/x/y/z", "x", "y", "z"},
}

func clearGetter(ev Event) Event {
	ev.Getter = nil
	return ev
}

func TestSplit(t *testing.T) {
	for _, vals := range Splits {
		path, exp := vals[0], vals[1:]
		got := split(path)
		assert.Equal(t, exp, got, path)
	}
}

func TestCheckBadPaths(t *testing.T) {
	for _, k := range BadPaths {
		err := checkPath(k)
		_, ok := err.(*BadPathError)
		assert.Tf(t, ok, "for path %q, got %T: %v", k, err, err)
	}
}

func TestCheckGoodPaths(t *testing.T) {
	for _, k := range GoodPaths {
		err := checkPath(k)
		assert.Equalf(t, nil, err, "for path %q", k)
	}
}

func TestEncodeSet(t *testing.T) {
	for _, kvcm := range SetKVCMs {
		k, v, c, exp := kvcm[0], kvcm[1], kvcm[2], kvcm[3]
		got, err := EncodeSet(k, v, c)
		assert.Equal(t, nil, err)
		assert.Equal(t, exp, got)
	}
}

func BenchmarkEncodeSet(b *testing.B) {
	for i := 0; i < b.N; i++ {
		EncodeSet("/x", "a", Clobber)
	}
}

func TestEncodeDel(t *testing.T) {
	for _, kcm := range DelKCMs {
		k, c, exp := kcm[0], kcm[1], kcm[2]
		got, err := EncodeDel(k, c)
		assert.Equal(t, nil, err)
		assert.Equal(t, exp, got)
	}
}

func BenchmarkEncodeDel(b *testing.B) {
	for i := 0; i < b.N; i++ {
		EncodeDel("/x", Clobber)
	}
}

func TestDecodeSet(t *testing.T) {
	for _, kvcm := range SetKVCMs {
		expk, expv, expc, m := kvcm[0], kvcm[1], kvcm[2], kvcm[3]
		gotk, gotv, gotc, keep, err := decode(m)
		assert.Equal(t, nil, err)
		assert.Equal(t, true, keep, "keep from "+m)
		assert.Equal(t, expk, gotk, "key from "+m)
		assert.Equal(t, expv, gotv, "value from "+m)
		assert.Equal(t, expc, gotc, "cas from "+m)
	}
}

func TestDecodeDel(t *testing.T) {
	for _, kcm := range DelKCMs {
		expk, expc, m := kcm[0], kcm[1], kcm[2]
		gotk, gotv, gotc, keep, err := decode(m)
		assert.Equal(t, nil, err)
		assert.Equal(t, false, keep, "keep from "+m)
		assert.Equal(t, expk, gotk, "key from "+m)
		assert.Equal(t, "", gotv, "value from "+m)
		assert.Equal(t, expc, gotc, "cas from "+m)
	}
}

func TestDecodeBadInstructions(t *testing.T) {
	for _, m := range BadInstructions {
		_, _, _, _, err := decode(m)
		_, ok := err.(*BadPathError)
		assert.Tf(t, ok, "for mut %q, got %T: %v", m, err, err)
	}
}

func TestDecodeBadMutations(t *testing.T) {
	for _, m := range BadMutations {
		_, _, _, _, err := decode(m)
		assert.Equal(t, ErrBadMutation, err)
	}
}

func TestGetMissing(t *testing.T) {
	s := New()
	v, cas := s.Get("/x")
	assert.Equal(t, Missing, cas)
	assert.Equal(t, []string{""}, v)
}

func TestGet(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Sync(1)
	v, cas := s.Get("/x")
	assert.Equal(t, "1", cas)
	assert.Equal(t, []string{"a"}, v)
}

func TestGetDeleted(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Apply(2, MustEncodeDel("/x", Clobber))
	s.Sync(2)
	v, cas := s.Get("/x")
	assert.Equal(t, Missing, cas)
	assert.Equal(t, []string{""}, v)
}

func TestApplyInOrder(t *testing.T) {
	s := New()
	s.Apply(1, MustEncodeSet("/x", "a", Clobber))
	s.Apply(2, MustEncodeSet("/x", "b", Clobber))
	s.Sync(2)
	v, cas := s.Get("/x")
	assert.Equal(t, "2", cas)
	assert.Equal(t, []string{"b"}, v)
}

func BenchmarkApply(b *testing.B) {
	s := New()
	mut := MustEncodeSet("/x", "a", Clobber)

	n := uint64(b.N + 1)
	for i := uint64(1); i < n; i++ {
		s.Apply(i, mut)
	}
}

func TestGetSync(t *testing.T) {
	chV := make(chan []string)
	chCas := make(chan string)
	s := New()
	go func() {
		s.Sync(5)
		v, cas := s.Get("/x")
		chV <- v
		chCas <- cas
{'fraction_non_alphanumeric': 0.24723557692307693, 'fraction_numerical': 0.011057692307692308, 'mean_word_length': 3.4688506981740064, 'pattern_counts': {'":': 24, '<': 10, '<?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': '3792611', 'n_tokens_mistral': 4000, 'n_tokens_neox': 3840, 'n_words': 915}