| # Test Data for CLDR MessageFormat 2.0 Tech Preview |
| |
| For information about MessageFormat 2.0, see [Unicode Locale Data Markup Language (LDML): Part 9: Message Format](../../../docs/ldml/tr35-messageFormat.md) |
| |
| The tests in the `./tests/` directory were originally copied from the [messageformat project](https://github.com/messageformat/messageformat/tree/11c95dab2b25db8454e49ff4daadb817e1d5b770/packages/mf2-messageformat/src/__fixtures) |
| and are here relicensed by their original author (Eemeli Aro) under the Unicode License. |
| |
| These test files are intended to be useful for testing multiple different message processors in different ways: |
| |
| - `syntax.json` — Test cases that do not depend on any registry definitions. |
| |
| - `syntax-errors.json` — Strings that should produce a Syntax Error when parsed. |
| |
| - `data-model-errors.json` - Strings that should produce a Data Model Error when processed. |
| Error names are defined in ["MessageFormat 2.0 Errors"](../spec/errors.md) in the spec. |
| |
| - `functions/` — Test cases that correspond to built-in functions. |
| The behaviour of the built-in formatters is implementation-specific so the `exp` field is often |
| omitted and assertions are made on error cases. |
| |
| Some examples of test harnesses using these tests, from the source repository: |
| |
| - [CST parse/stringify tests](https://github.com/messageformat/messageformat/blob/11c95dab2b25db8454e49ff4daadb817e1d5b770/packages/mf2-messageformat/src/cst/cst.test.ts) |
| - [Data model stringify tests](https://github.com/messageformat/messageformat/blob/11c95dab2b25db8454e49ff4daadb817e1d5b770/packages/mf2-messageformat/src/data-model/stringify.test.ts) |
| - [Formatting tests](https://github.com/messageformat/messageformat/blob/11c95dab2b25db8454e49ff4daadb817e1d5b770/packages/mf2-messageformat/src/messageformat.test.ts) |
| |
| A [JSON schema](./schemas/) is included for the test files in this repository. |
| ## Error Codes |
| |
| The following table relates the error names used in the [JSON schema](./schemas/) |
| to the error names used in ["MessageFormat 2.0 Errors"](../spec/errors.md) in the spec. |
| |
| | Spec | Schema | |
| | --------------------------- | --------------------------- | |
| | Bad Operand | bad-operand | |
| | Bad Option | bad-option | |
| | Bad Selector | bad-selector | |
| | Bad Variant Key | bad-variant-key | |
| | Duplicate Declaration | duplicate-declaration | |
| | Duplicate Option Name | duplicate-option-name | |
| | Duplicate Variant | duplicate-variant | |
| | Missing Fallback Variant | missing-fallback-variant | |
| | Missing Selector Annotation | missing-selector-annotation | |
| | Syntax Error | syntax-error | |
| | Unknown Function | unknown-function | |
| | Unresolved Variable | unresolved-variable | |
| | Variant Key Mismatch | variant-key-mismatch | |
| |
| The "Message Function Error" error name used in the spec |
| is not included in the schema, |
| as it is intended to be an umbrella category |
| for implementation-specific errors. |
| |
| ## 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 following _options_ are available on `:test:function`: |
| - `decimalPlaces`, a _digit size option_ for which only `0` and `1` are valid values. |
| - `0` |
| - `1` |
| - `fails` |
| - `never` (default) |
| - `select` |
| - `format` |
| - `always` |
| |
| All other _options_ and their values are ignored. |
| |
| #### Behavior |
| |
| When resolving a `:test:function` expression, |
| its `Input`, `DecimalPlaces`, `FailsFormat`, and `FailsSelect` values are determined as follows: |
| |
| 1. Let `DecimalPlaces` be 0. |
| 1. Let `FailsFormat` be `false`. |
| 1. Let `FailsSelect` be `false`. |
| 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. Set `FailsFormat` to be `FailsFormat` value of `arg`. |
| 1. Set `FailsSelect` to be `FailsSelect` 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_. |
| 1. If the `fails` _option_ is set, then |
| 1. If its value resolves to the string `'always'`, then |
| 1. Set `FailsFormat` to be `true`. |
| 1. Set `FailsSelect` to be `true`. |
| 1. Else if its value resolves to the string `'format'`, then |
| 1. Set `FailsFormat` to be `true`. |
| 1. Else if its value resolves to the string `'select'`, then |
| 1. Set `FailsSelect` to be `true`. |
| 1. Else if its value does not resolve to the string `'never'`, then |
| 1. Emit "bad-option" _Resolution Error_. |
| |
| 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`, `DecimalPlaces` and `FailsSelect` values. |
| |
| - If `FailsSelect` is `true`, |
| calling the method will fail and not return any value. |
| - 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. |
| |
| If `FailsFormat` is `true`, |
| attempting to format the _placeholder_ to any formatting target will fail. |
| |
| ### `: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. |