mirror of https://github.com/0xERR0R/blocky.git
191 lines
4.3 KiB
Go
191 lines
4.3 KiB
Go
package parsers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
. "github.com/0xERR0R/blocky/helpertest"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("ForEach", func() {
|
|
var lines SeriesParser[string]
|
|
|
|
BeforeEach(func() {
|
|
lines = Lines(linesReader(
|
|
"first",
|
|
"second",
|
|
"third",
|
|
))
|
|
})
|
|
|
|
It("should iterate and hide io.EOF", func() {
|
|
list := iteratorToList(func(cb func(string) error) error {
|
|
return ForEach(context.Background(), lines, cb)
|
|
})
|
|
|
|
Expect(list).Should(Equal([]string{"first", "second", "third"}))
|
|
})
|
|
|
|
It("should return callback errors", func() {
|
|
expectedErr := errors.New("fail")
|
|
|
|
err := ForEach(context.Background(), lines, func(line string) error {
|
|
return expectedErr
|
|
})
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err).Should(MatchError(expectedErr))
|
|
Expect(err.Error()).Should(HavePrefix("line 1: "))
|
|
})
|
|
|
|
It("should return parser errors", func() {
|
|
lines := Hosts(linesReader(
|
|
"invalid line",
|
|
))
|
|
|
|
err := ForEach(context.Background(), lines, func(*HostsIterator) error {
|
|
Fail("callback should not be called")
|
|
|
|
return nil
|
|
})
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err.Error()).Should(HavePrefix("line 1: "))
|
|
})
|
|
|
|
It("should stop when context is done", func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
err := ForEach(ctx, lines, func(line string) error {
|
|
if ctx.Err() != nil {
|
|
Fail("callback should not be called")
|
|
}
|
|
|
|
cancel()
|
|
|
|
return nil
|
|
})
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err).Should(MatchError(context.Canceled))
|
|
Expect(err.Error()).Should(HavePrefix("line 1: "))
|
|
})
|
|
|
|
It("should not start if context is already done", func() {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
err := ForEach(ctx, lines, func(line string) error {
|
|
Fail("callback should not be called")
|
|
|
|
return nil
|
|
})
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err).Should(MatchError(context.Canceled))
|
|
Expect(err.Error()).Should(HavePrefix("line 0: "))
|
|
})
|
|
})
|
|
|
|
var _ = Describe("ErrWithPosition", func() {
|
|
When("err is nil", func() {
|
|
It("returns nil", func() {
|
|
inner := errors.New("inner")
|
|
lines := Lines(linesReader(
|
|
"first",
|
|
"second",
|
|
))
|
|
|
|
_, err := lines.Next(context.Background())
|
|
Expect(err).Should(Succeed())
|
|
|
|
err = ErrWithPosition(lines, inner)
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err.Error()).Should(Equal("line 1: inner"))
|
|
|
|
_, err = lines.Next(context.Background())
|
|
Expect(err).Should(Succeed())
|
|
|
|
err = ErrWithPosition(lines, inner)
|
|
Expect(err).ShouldNot(Succeed())
|
|
Expect(err.Error()).Should(Equal("line 2: inner"))
|
|
})
|
|
})
|
|
|
|
When("err is nil", func() {
|
|
It("returns nil", func() {
|
|
err := ErrWithPosition[any](nil, nil)
|
|
Expect(err).Should(Succeed())
|
|
})
|
|
})
|
|
})
|
|
|
|
var _ = Describe("NonResumableError", func() {
|
|
Describe("IsNonResumableErr", func() {
|
|
It("should return the inner error", func() {
|
|
inner := errors.New("inner")
|
|
Expect(IsNonResumableErr(inner)).Should(BeFalse())
|
|
|
|
err := NewNonResumableError(inner)
|
|
Expect(IsNonResumableErr(err)).Should(BeTrue())
|
|
})
|
|
})
|
|
|
|
Describe("Error", func() {
|
|
It("should return error message", func() {
|
|
inner := errors.New("inner")
|
|
|
|
err := NewNonResumableError(inner)
|
|
Expect(err.Error()).Should(Equal("non resumable parse error: inner"))
|
|
})
|
|
})
|
|
|
|
Describe("Unwrap", func() {
|
|
It("should return the inner error", func() {
|
|
inner := errors.New("inner")
|
|
|
|
err := NewNonResumableError(inner)
|
|
Expect(errors.Unwrap(err)).Should(Equal(inner))
|
|
Expect(errors.Is(err, inner)).Should(BeTrue())
|
|
})
|
|
})
|
|
})
|
|
|
|
func iteratorToList[T any](forEach func(func(T) error) error) []T {
|
|
var res []T
|
|
|
|
err := forEach(func(t T) error {
|
|
res = append(res, t)
|
|
|
|
return nil
|
|
})
|
|
Expect(err).Should(Succeed())
|
|
|
|
return res
|
|
}
|
|
|
|
type mockParser[T any] struct{ MockCallSequence[T] }
|
|
|
|
func newMockParser[T any](driver func(chan<- T, chan<- error)) SeriesParser[T] {
|
|
return &mockParser[T]{NewMockCallSequence(driver)}
|
|
}
|
|
|
|
func (m *mockParser[T]) Next(ctx context.Context) (_ T, rerr error) {
|
|
defer func() {
|
|
if rerr != nil && IsNonResumableErr(rerr) {
|
|
m.Close()
|
|
}
|
|
}()
|
|
|
|
if err := ctx.Err(); err != nil {
|
|
var zero T
|
|
|
|
return zero, NewNonResumableError(err)
|
|
}
|
|
|
|
return m.Call()
|
|
}
|
|
|
|
func (m *mockParser[T]) Position() string {
|
|
return fmt.Sprintf("call %d", m.CallCount())
|
|
}
|