-- cue.mod/module.cue --
module: "cuelang.org/error"
language: version: "v0.15.0"
-- in.cue --
selection: {
	dropError: 1 | error("drop me") @test(eq, 1)

	useCustomError: 1&2 | error("use me") @test(err, code=eval, contains="use me", pos=[0:24, 0:18, 0:20])

	twoCustomErrors: 1&2 | error("error one") | error("error two") @test(err, code=eval, contains="empty disjunction",
		suberr=(code=eval, contains="error one", pos=[0:25]),
		suberr=(code=eval, contains="error two", pos=[0:46]),
	)

	x: int
	dropIncomplete: x + 1 | error("user msg: x + 1 failed") @test(err, code=incomplete, contains="user msg: x + 1 failed", pos=[0:26, -1:5])
}

interpolation: {
	a: {b: int}
	world: "world" @test(eq, "world")

	substituteAll: a.notExist | error("hello \(world)") @test(err, code=incomplete, contains="hello world", pos=[0:30])

	substituteFail: a.b + 1 | a.notExist | error("reference failed: \(a.b) | \(a.notExist)") @test(err, code=incomplete, contains="reference failed:", pos=[0:41, -5:9, 0:77])

	// When the error() message itself contains an error,
	// the custom error should not be thrown away.
	// For comparison, without interpolation:
	errorNoInterpolation: "a" | "b" | error("custom")
	errorNoInterpolation: "c" @test(err, code=eval, contains="custom", pos=[-1:36, -1:24, 0:24])

	// When the struct interpolation fails, the custom error should
	// still be shown rather than being replaced by the interpolation error.
	errorStructInterpolation: "a" | "b" | error("custom: \({x: 1})")
	errorStructInterpolation: "c" @test(err, code=eval, contains="custom: {x:1}", pos=[-1:40, -1:28, -1:57, 0:28])

	// When the interpolation always results in an error, the custom
	// error should still be shown.
	errorBottomInterpolation: "a" | "b" | error("custom: \(1 & 2)")
	errorBottomInterpolation: "c" @test(err, code=eval, contains="custom: (1 & 2)", pos=[-1:40, -1:28, -1:57, 0:28])
}
indirect: {
	x: error    @test(eq, error)
	y: x("msg") @test(err, code=user, contains="msg", pos=[0:5])
}
-- incomplete.cue --
import "struct"

// The custom error should not alter the type of error.
minFields: struct.MinFields(2) | error("should remain incomplete") @test(eq, struct.MinFields(2))
maxFields: a: 1 @test(eq, 1)

multi: struct.MinFields(2) | error("should remain incomplete") | error("second") @test(err, code=incomplete,
	pos=[0:8, 0:25, 4:8],
	suberr=(code=eval, contains="should remain incomplete", pos=[0:30]),
	suberr=(code=eval, contains="second", pos=[0:66]))
multi: a: 1

-- self.cue --
@experiment(aliasv2)

// When error() interpolates "self" which is the enclosing struct
// containing the error value itself (a cycle), the custom error
// should still be shown.
errorSelf: {
	v: "x" | "y" | error("bad: \(self)")
	v: "z"
	@test(err, code=eval, contains="bad:", pos=[1:17, 0:12, 1:5, 2:5])
}
-- issues.cue --
// issue4001: Tests that error() text is shown correctly when the message uses
// string concatenation with interpolation. https://cuelang.org/issue/4001
issue4001: {
	a: "b"
	a: int | error("error: "+"a='\(a)'") @test(err, code=eval, contains="error: a='b'", pos=[0:11, -1:5, 0:5])
}
// issue3983: Tests that multiple error() disjunctions aggregate all user-defined
// error messages correctly. https://cuelang.org/issue/3983
issue3983: {
	x: int | error("I wanted an integer")
	x: >10 | error("I wanted more than 10")
	x: <20 | error("I wanted less than 20")

	x: 3
	@test(err, code=eval, contains="2 errors in empty disjunction", pos=[2:5, 5:5],
		suberr=(code=eval, contains="I wanted an integer", hint="this could be dropped"),
		suberr=(code=eval, contains="I wanted more than 10"),
		hint="we could also include the third condition, if we want to be consistent.",
	)
}
// issue3984: Tests that error() shows all relevant source locations when the
// error builtin is used in a disjunction. https://cuelang.org/issue/3984
issue3984: {
	v: "a" | error("must be a")
	v: "b" @test(err, code=eval, contains="must be a", pos=[-1:11, -1:5, 0:5])
}
-- out/eval/stats --
Leaks:  3
Freed:  76
Reused: 57
Allocs: 22
Retain: 0

Unifications: 34
Conjuncts:    91
Disjuncts:    41
-- out/errors.txt --
[eval] selection.useCustomError: use me:
    ./in.cue:4:24
    ./in.cue:4:18
    ./in.cue:4:20
[eval] selection.twoCustomErrors: 2 errors in empty disjunction::
    ./in.cue:6:19
    ./in.cue:6:21
selection.twoCustomErrors: error one:
    ./in.cue:6:25
selection.twoCustomErrors: error two:
    ./in.cue:6:46
[incomplete] selection.dropIncomplete: user msg: x + 1 failed:
    ./in.cue:12:26
    ./in.cue:11:5
[incomplete] interpolation.substituteAll: hello world:
    ./in.cue:19:30
[incomplete] interpolation.substituteFail: reference failed: int | a.notExist:
    ./in.cue:21:41
    ./in.cue:16:9
    ./in.cue:21:77
[eval] interpolation.errorNoInterpolation: custom:
    ./in.cue:26:36
    ./in.cue:26:24
    ./in.cue:27:24
[eval] interpolation.errorStructInterpolation: custom: {x:1}:
    ./in.cue:31:40
    ./in.cue:31:28
    ./in.cue:31:57
    ./in.cue:32:28
[eval] interpolation.errorBottomInterpolation: custom: (1 & 2):
    ./in.cue:36:40
    ./in.cue:36:28
    ./in.cue:36:57
    ./in.cue:37:28
[user] indirect.y: msg:
    ./in.cue:41:5
[incomplete] multi: 2 errors in empty disjunction::
    ./incomplete.cue:7:8
    ./incomplete.cue:7:25
    ./incomplete.cue:11:8
multi: should remain incomplete:
    ./incomplete.cue:7:30
multi: second:
    ./incomplete.cue:7:66
[eval] issue4001.a: error: a='b':
    ./issues.cue:5:11
    ./issues.cue:4:5
    ./issues.cue:5:5
[eval] issue3983.x: 2 errors in empty disjunction::
    ./issues.cue:11:5
    ./issues.cue:14:5
issue3983.x: I wanted an integer:
    ./issues.cue:10:11
issue3983.x: I wanted more than 10:
    ./issues.cue:11:11
[eval] issue3984.v: must be a:
    ./issues.cue:24:11
    ./issues.cue:24:5
    ./issues.cue:25:5
[eval] errorSelf.v: bad: {v:_|_(errorSelf.v: bad: value at path 'errorSelf')}:
    ./self.cue:7:17
    ./self.cue:6:12
    ./self.cue:7:5
    ./self.cue:8:5
