corso/src/pkg/path/builder_test.go
ryanfkeepers dfd486cd41 distrubutes ServiceResource throughout path
Adds utilization of the ServiceResource struct to all
of the path package functionality.  In general, this
takes most instances where a service and resource
are requested, and replaces those values with a
slice of ServiceResource tuples.

To keep the review smaller, this change does not update
any packages outside of path.  Therefore the tests and
build are guaranteed to fail.  The next PR, which
updates all other packages with the changes, is
necessary for both PRs to move forward.
2023-08-10 14:57:04 -06:00

378 lines
9.3 KiB
Go

package path
import (
"fmt"
"strings"
"testing"
"github.com/alcionai/clues"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
)
type BuilderUnitSuite struct {
tester.Suite
}
func TestBuilderUnitSuite(t *testing.T) {
suite.Run(t, &BuilderUnitSuite{Suite: tester.NewUnitSuite(t)})
}
// set the clues hashing to mask for the span of this suite
func (suite *BuilderUnitSuite) SetupSuite() {
clues.SetHasher(clues.HashCfg{HashAlg: clues.Flatmask})
}
// revert clues hashing to plaintext for all other tests
func (suite *BuilderUnitSuite) TeardownSuite() {
clues.SetHasher(clues.NoHash())
}
func (suite *BuilderUnitSuite) TestAppend() {
table := append(append([]testData{}, genericCases...), basicUnescapedInputs...)
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
p := Builder{}.Append(test.input...)
assert.Equal(t, test.expectedString, p.String())
})
}
}
func (suite *BuilderUnitSuite) TestAppendItem() {
t := suite.T()
srs, err := NewServiceResources(ExchangeService, "ro")
require.NoError(t, err, clues.ToCore(err))
p, err := Build("t", srs, EmailCategory, false, "foo", "bar")
require.NoError(t, err, clues.ToCore(err))
pb := p.ToBuilder()
assert.Equal(t, pb.String(), p.String())
pb = pb.Append("qux")
p, err = p.AppendItem("qux")
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, pb.String(), p.String())
_, err = p.AppendItem("fnords")
require.Error(t, err, clues.ToCore(err))
}
func (suite *BuilderUnitSuite) TestUnescapeAndAppend() {
table := append(append([]testData{}, genericCases...), basicEscapedInputs...)
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
p, err := Builder{}.UnescapeAndAppend(test.input...)
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, test.expectedString, p.String())
})
}
}
func (suite *BuilderUnitSuite) TestEscapedFailure() {
target := "i_s"
for c := range charactersToEscape {
suite.Run(fmt.Sprintf("Unescaped-%c", c), func() {
tmp := strings.ReplaceAll(target, "_", string(c))
_, err := Builder{}.UnescapeAndAppend("this", tmp, "path")
assert.Errorf(suite.T(), err, "path with unescaped %s did not error", string(c))
})
}
}
func (suite *BuilderUnitSuite) TestBadEscapeSequenceErrors() {
target := `i\_s/a`
notEscapes := []rune{'a', 'b', '#', '%'}
for _, c := range notEscapes {
suite.Run(fmt.Sprintf("Escaped-%c", c), func() {
tmp := strings.ReplaceAll(target, "_", string(c))
_, err := Builder{}.UnescapeAndAppend("this", tmp, "path")
assert.Errorf(
suite.T(),
err,
"path with bad escape sequence %c%c did not error",
escapeCharacter,
c)
})
}
}
func (suite *BuilderUnitSuite) TestTrailingEscapeChar() {
base := []string{"this", "is", "a", "path"}
for i := 0; i < len(base); i++ {
suite.Run(fmt.Sprintf("Element%v", i), func() {
path := make([]string, len(base))
copy(path, base)
path[i] = path[i] + string(escapeCharacter)
_, err := Builder{}.UnescapeAndAppend(path...)
assert.Error(
suite.T(),
err,
"path with trailing escape character did not error")
})
}
}
func (suite *BuilderUnitSuite) TestElements() {
table := []struct {
name string
input []string
output []string
pathFunc func(elements []string) (*Builder, error)
}{
{
name: "SimpleEscapedPath",
input: []string{"this", "is", "a", "path"},
output: []string{"this", "is", "a", "path"},
pathFunc: func(elements []string) (*Builder, error) {
return Builder{}.UnescapeAndAppend(elements...)
},
},
{
name: "SimpleUnescapedPath",
input: []string{"this", "is", "a", "path"},
output: []string{"this", "is", "a", "path"},
pathFunc: func(elements []string) (*Builder, error) {
return Builder{}.Append(elements...), nil
},
},
{
name: "EscapedPath",
input: []string{"this", `is\/`, "a", "path"},
output: []string{"this", "is/", "a", "path"},
pathFunc: func(elements []string) (*Builder, error) {
return Builder{}.UnescapeAndAppend(elements...)
},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
p, err := test.pathFunc(test.input)
require.NoError(t, err, clues.ToCore(err))
assert.Equal(t, Elements(test.output), p.Elements())
})
}
}
func (suite *BuilderUnitSuite) TestPopFront() {
table := []struct {
name string
base *Builder
expectedString string
}{
{
name: "Empty",
base: &Builder{},
expectedString: "",
},
{
name: "OneElement",
base: Builder{}.Append("something"),
expectedString: "",
},
{
name: "TwoElements",
base: Builder{}.Append("something", "else"),
expectedString: "else",
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
assert.Equal(t, test.expectedString, test.base.PopFront().String())
})
}
}
func (suite *BuilderUnitSuite) TestShortRef() {
table := []struct {
name string
inputElements []string
expectedLen int
}{
{
name: "PopulatedPath",
inputElements: []string{"this", "is", "a", "path"},
expectedLen: shortRefCharacters,
},
{
name: "EmptyPath",
inputElements: nil,
expectedLen: 0,
},
}
for _, test := range table {
suite.Run(test.name, func() {
pb := Builder{}.Append(test.inputElements...)
ref := pb.ShortRef()
assert.Len(suite.T(), ref, test.expectedLen)
})
}
}
func (suite *BuilderUnitSuite) TestShortRefIsStable() {
t := suite.T()
pb := Builder{}.Append("this", "is", "a", "path")
prevRef := pb.ShortRef()
assert.Len(t, prevRef, shortRefCharacters)
for i := 0; i < 5; i++ {
ref := pb.ShortRef()
assert.Len(t, ref, shortRefCharacters)
assert.Equal(t, prevRef, ref, "ShortRef changed between calls")
prevRef = ref
}
}
func (suite *BuilderUnitSuite) TestShortRefIsUnique() {
pb1 := Builder{}.Append("this", "is", "a", "path")
pb2 := pb1.Append("also")
require.NotEqual(suite.T(), pb1, pb2)
assert.NotEqual(suite.T(), pb1.ShortRef(), pb2.ShortRef())
}
// TestShortRefUniqueWithEscaping tests that two paths that output the same
// unescaped string but different escaped strings have different shortrefs. This
// situation can occur when one path has embedded path separators while the
// other does not but contains the same characters.
func (suite *BuilderUnitSuite) TestShortRefUniqueWithEscaping() {
pb1 := Builder{}.Append(`this`, `is`, `a`, `path`)
pb2 := Builder{}.Append(`this`, `is/a`, `path`)
require.NotEqual(suite.T(), pb1, pb2)
assert.NotEqual(suite.T(), pb1.ShortRef(), pb2.ShortRef())
}
func (suite *BuilderUnitSuite) TestFolder() {
table := []struct {
name string
p func(t *testing.T) Path
escape bool
expectFolder string
expectSplit []string
}{
{
name: "clean path",
p: func(t *testing.T) Path {
p, err := Builder{}.
Append("a", "b", "c").
ToDataLayerExchangePathForCategory("t", "u", EmailCategory, false)
require.NoError(t, err, clues.ToCore(err))
return p
},
expectFolder: "a/b/c",
expectSplit: []string{"a", "b", "c"},
},
{
name: "clean path escaped",
p: func(t *testing.T) Path {
p, err := Builder{}.
Append("a", "b", "c").
ToDataLayerExchangePathForCategory("t", "u", EmailCategory, false)
require.NoError(t, err, clues.ToCore(err))
return p
},
escape: true,
expectFolder: "a/b/c",
expectSplit: []string{"a", "b", "c"},
},
{
name: "escapable path",
p: func(t *testing.T) Path {
p, err := Builder{}.
Append("a/", "b", "c").
ToDataLayerExchangePathForCategory("t", "u", EmailCategory, false)
require.NoError(t, err, clues.ToCore(err))
return p
},
expectFolder: "a//b/c",
expectSplit: []string{"a", "b", "c"},
},
{
name: "escapable path escaped",
p: func(t *testing.T) Path {
p, err := Builder{}.
Append("a/", "b", "c").
ToDataLayerExchangePathForCategory("t", "u", EmailCategory, false)
require.NoError(t, err, clues.ToCore(err))
return p
},
escape: true,
expectFolder: "a\\//b/c",
expectSplit: []string{"a\\/", "b", "c"},
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
p := test.p(t)
result := p.Folder(test.escape)
assert.Equal(t, test.expectFolder, result)
assert.Equal(t, test.expectSplit, Split(result))
})
}
}
func (suite *BuilderUnitSuite) TestPIIHandling() {
t := suite.T()
srs, err := NewServiceResources(ExchangeService, "ro")
require.NoError(t, err, clues.ToCore(err))
p, err := Build("t", srs, EventsCategory, true, "dir", "item")
require.NoError(t, err)
table := []struct {
name string
p Path
expect string
expectPlain string
}{
{
name: "standard path",
p: p,
expect: "***/exchange/***/events/***/***",
expectPlain: "t/exchange/ro/events/dir/item",
},
}
for _, test := range table {
suite.Run(test.name, func() {
t := suite.T()
assert.Equal(t, test.expect, test.p.Conceal(), "conceal")
assert.Equal(t, test.expectPlain, test.p.String(), "string")
assert.Equal(t, test.expect, fmt.Sprintf("%s", test.p), "fmt %%s")
assert.Equal(t, test.expect, fmt.Sprintf("%+v", test.p), "fmt %%+v")
assert.Equal(t, test.expectPlain, test.p.PlainString(), "plain")
})
}
}