mirror of
https://github.com/boolean-maybe/tiki
synced 2026-04-21 13:37:20 +00:00
170 lines
4.6 KiB
Go
170 lines
4.6 KiB
Go
package ruki
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestExecuteRawStatementRejectsCallBeforeEvaluation(t *testing.T) {
|
|
e := newTestExecutor()
|
|
p := newTestParser()
|
|
|
|
stmt, err := p.ParseStatement(`select where 1 = 2 and call("echo hello") = "x"`)
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
_, err = e.Execute(stmt, makeTasks())
|
|
if err == nil {
|
|
t.Fatal("expected semantic validation error")
|
|
}
|
|
if !strings.Contains(err.Error(), "call() is not supported yet") {
|
|
t.Fatalf("expected call() semantic validation error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteRawStatementRejectsIDOutsidePluginRuntime(t *testing.T) {
|
|
e := newTestExecutor()
|
|
p := newTestParser()
|
|
|
|
stmt, err := p.ParseStatement(`select where 1 = 2 and id() = "TIKI-000001"`)
|
|
if err != nil {
|
|
t.Fatalf("parse: %v", err)
|
|
}
|
|
_, err = e.Execute(stmt, makeTasks())
|
|
if err == nil {
|
|
t.Fatal("expected semantic validation error")
|
|
}
|
|
if !strings.Contains(err.Error(), "id() is only available in plugin runtime") {
|
|
t.Fatalf("expected id() runtime error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteValidatedStatementRuntimeMismatch(t *testing.T) {
|
|
e := newTestExecutor()
|
|
p := newTestParser()
|
|
|
|
validated, err := p.ParseAndValidateStatement(`select`, ExecutorRuntimePlugin)
|
|
if err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
_, err = e.Execute(validated, makeTasks())
|
|
if err == nil {
|
|
t.Fatal("expected runtime mismatch error")
|
|
}
|
|
var mismatch *RuntimeMismatchError
|
|
if !errors.As(err, &mismatch) {
|
|
t.Fatalf("expected RuntimeMismatchError, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteUnsealedValidatedStatementRejected(t *testing.T) {
|
|
e := newTestExecutor()
|
|
unsealed := &ValidatedStatement{
|
|
statement: &Statement{Select: &SelectStmt{}},
|
|
}
|
|
|
|
_, err := e.Execute(unsealed, makeTasks())
|
|
if err == nil {
|
|
t.Fatal("expected unvalidated wrapper error")
|
|
}
|
|
var unvalidated *UnvalidatedWrapperError
|
|
if !errors.As(err, &unvalidated) {
|
|
t.Fatalf("expected UnvalidatedWrapperError, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteValidatedCreateRequiresTemplate(t *testing.T) {
|
|
e := newTestExecutor()
|
|
p := newTestParser()
|
|
|
|
validated, err := p.ParseAndValidateStatement(`create title="x"`, ExecutorRuntimeCLI)
|
|
if err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
_, err = e.Execute(validated, nil)
|
|
if err == nil {
|
|
t.Fatal("expected missing create template error")
|
|
}
|
|
var missing *MissingCreateTemplateError
|
|
if !errors.As(err, &missing) {
|
|
t.Fatalf("expected MissingCreateTemplateError, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecutePluginIDRequiresSelectedTaskID(t *testing.T) {
|
|
p := newTestParser()
|
|
e := NewExecutor(testSchema{}, func() string { return "alice" }, ExecutorRuntime{Mode: ExecutorRuntimePlugin})
|
|
|
|
validated, err := p.ParseAndValidateStatement(`select where id() = "TIKI-000001"`, ExecutorRuntimePlugin)
|
|
if err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
_, err = e.Execute(validated, makeTasks())
|
|
if err == nil {
|
|
t.Fatal("expected missing selected task id error")
|
|
}
|
|
var missing *MissingSelectedTaskIDError
|
|
if !errors.As(err, &missing) {
|
|
t.Fatalf("expected MissingSelectedTaskIDError, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidatedTriggerCloneIsolated(t *testing.T) {
|
|
p := newTestParser()
|
|
|
|
validated, err := p.ParseAndValidateTrigger(`before create deny "blocked"`, ExecutorRuntimeEventTrigger)
|
|
if err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
clone := validated.TriggerClone()
|
|
if clone == nil {
|
|
t.Fatal("expected non-nil trigger clone")
|
|
return
|
|
}
|
|
|
|
clone.Timing = "after"
|
|
clone.Event = "delete"
|
|
clone.Deny = nil
|
|
|
|
after := validated.TriggerClone()
|
|
if after == nil {
|
|
t.Fatal("expected non-nil trigger clone after mutation")
|
|
return
|
|
}
|
|
if after.Timing != "before" || after.Event != "create" {
|
|
t.Fatalf("validated trigger was mutated: timing=%q event=%q", after.Timing, after.Event)
|
|
}
|
|
if after.Deny == nil || *after.Deny != "blocked" {
|
|
t.Fatalf("expected deny message to remain unchanged, got %#v", after.Deny)
|
|
}
|
|
}
|
|
|
|
func TestValidatedTimeTriggerCloneIsolated(t *testing.T) {
|
|
p := newTestParser()
|
|
|
|
validated, err := p.ParseAndValidateTimeTrigger(`every 2day create title="x"`, ExecutorRuntimeTimeTrigger)
|
|
if err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
clone := validated.TimeTriggerClone()
|
|
if clone == nil {
|
|
t.Fatal("expected non-nil time trigger clone")
|
|
return
|
|
}
|
|
|
|
clone.Interval = DurationLiteral{Value: 9, Unit: "week"}
|
|
clone.Action = nil
|
|
|
|
after := validated.TimeTriggerClone()
|
|
if after == nil {
|
|
t.Fatal("expected non-nil time trigger clone after mutation")
|
|
return
|
|
}
|
|
if after.Interval.Value != 2 || after.Interval.Unit != "day" {
|
|
t.Fatalf("validated time trigger interval was mutated: %+v", after.Interval)
|
|
}
|
|
if after.Action == nil || after.Action.Create == nil {
|
|
t.Fatal("expected action to remain unchanged")
|
|
}
|
|
}
|