diff --git a/test/README.md b/test/README.md index 4d69851c2..0a43cef9c 100644 --- a/test/README.md +++ b/test/README.md @@ -23,3 +23,103 @@ Some examples of test harnesses using these tests, from the source repository: A [JSON schema](./schemas/) is included for the test files in this repository. For users of Visual Studio Code, a [settings file](./.vscode/settings.json) is included that enables schema validation while editing the test files. + +## Test Functions + +As the behaviour of some of the default registry _functions_ +such as `:number` and `:datetime` +is dependent on locale-specific data and may vary between implementations, +the following _functions_ are defined for **test use only**: + +### `:test:function` + +This function is valid both as a _selector_ and as a _formatter_. + +#### Operands + +The function `:test:function` requires a [Number Operand](/spec/registry.md#number-operands) as its _operand_. + +#### Options + +The only _option_ `:test:function` recognizes is `decimalPlaces`, +a _digit size option_ for which only `0` and `1` are valid values. + +All other _options_ and their values are ignored. + +#### Behavior + +When resolving a `:test:function` expression, +its `Input` and `DecimalPlaces` values are determined as follows: + +1. Let `DecimalPlaces` be 0. +1. Let `arg` be the resolved value of the _expression_ _operand_. +1. If `arg` is the resolved value of an _expression_ + with a `:test:function`, `:test:select`, or `:test:format` _annotation_ + for which resolution has succeeded, then + 1. Let `Input` be the `Input` value of `arg`. + 1. Set `DecimalPlaces` to be `DecimalPlaces` value of `arg`. +1. Else if `arg` is a numerical value + or a string matching the `number-literal` production, then + 1. Let `Input` be the numerical value of `arg`. +1. Else, + 1. Emit "bad-input" _Resolution Error_. + 1. Use a _fallback value_ as the resolved value of the _expression_. + Further steps of this algorithm are not followed. +1. If the `decimalPlaces` _option_ is set, then + 1. If its value resolves to a numerical integer value 0 or 1 + or their corresponding string representations `'0'` or `'1'`, then + 1. Set `DecimalPlaces` to be the numerical value of the _option_. + 1. Else if its value is not an unresolved value set by _option resolution_, + 1. Emit "bad-option" _Resolution Error_. + 1. Use a _fallback value_ as the resolved value of the _expression_. + +When `:test:function` is used as a _selector_, +the behaviour of calling it as the `rv` value of MatchSelectorKeys(`rv`, `keys`) +(see [Resolve Preferences](/spec/formatting.md#resolve-preferences) for more information) +depends on its `Input` and `DecimalPlaces` values. + +- If the `Input` is 1 and `DecimalPlaces` is 1, + the method will return some slice of the list « `'1.0'`, `'1'` », + depending on whether those values are included in `keys`. +- If the `Input` is 1 and `DecimalPlaces` is 0, + the method will return the list « `'1'` » if `keys` includes `'1'`, or an empty list otherwise. +- If the `Input` is any other value, the method will return an empty list. + +When an _expression_ with a `:test:function` _annotation_ is assigned to a _variable_ by a _declaration_ +and that _variable_ is used as an _option_ value, +its resolved value is the `Input` value. + +When `:test:function` is used as a _formatter_, +a _placeholder_ resolving to a value with a `:test:function` _expression_ +is formatted as a concatenation of the following parts: + +1. If `Input` is less than 0, the character `-` U+002D Hyphen-Minus. +1. The truncated absolute integer value of `Input`, i.e. floor(abs(`Input`)), + formatted as a sequence of decimal digit characters (U+0030...U+0039). +1. If `DecimalPlaces` is 1, then + 1. The character `.` U+002E Full Stop. + 1. The single decimal digit character representing the value floor((abs(`Input`) - floor(abs(`Input`))) \* 10) + +If the formatting target is a sequence of parts, +each of the above parts will be emitted separately +rather than being concatenated into a single string. + + +### `:test:select` + +This _function_ accepts the same _operands_ and _options_, +and behaves exactly the same as `:test:function`, +except that it cannot be used for formatting. + +When `:test:select` is used as a _formatter_, +a "not-formattable" error is emitted and the _placeholder_ is formatted with +a _fallback value_. + +### `:test:format` + +This _function_ accepts the same _operands_ and _options_, +and behaves exactly the same as `:test:function`, +except that it cannot be used for selection. + +When `:test:format` is used as a _selector_, +the steps under 2.iii. of [Resolve Selectors](/spec/formatting.md#resolve-selectors) are followed.