Skip to content

Commit 5d82d17

Browse files
srl295Squash Bot
authored andcommitted
ICU-23424 C: MF2: Allow overriding standard functions
See #4041
1 parent 3ffacba commit 5d82d17

3 files changed

Lines changed: 111 additions & 3 deletions

File tree

icu4c/source/i18n/messageformat2_formatter.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,16 +281,16 @@ namespace message2 {
281281
UErrorCode& status) const {
282282
NULL_ON_ERROR(status);
283283

284-
if (isBuiltInFunction(functionName)) {
285-
return standardMFFunctionRegistry.getFunction(functionName);
286-
}
287284
if (hasCustomMFFunctionRegistry()) {
288285
const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry();
289286
Function* function = customMFFunctionRegistry.getFunction(functionName);
290287
if (function != nullptr) {
291288
return function;
292289
}
293290
}
291+
if (isBuiltInFunction(functionName)) {
292+
return standardMFFunctionRegistry.getFunction(functionName);
293+
}
294294
// Either there is no custom function registry and the function
295295
// isn't built-in, or the function doesn't exist in either the built-in
296296
// or custom registry.

icu4c/source/test/intltest/messageformat2test.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ TestMessageFormat2::runIndexedTest(int32_t index, UBool exec,
3131
TESTCASE_AUTO(testLowLoneSurrogate);
3232
TESTCASE_AUTO(testLoneSurrogateInQuotedLiteral);
3333
TESTCASE_AUTO(dataDrivenTests);
34+
TESTCASE_AUTO(testOverrideFunctions);
3435
TESTCASE_AUTO_END;
3536
}
3637

@@ -479,6 +480,112 @@ void TestMessageFormat2::dataDrivenTests() {
479480
jsonTestsFromFiles(errorCode);
480481
}
481482

483+
class FixedDateValue : public FunctionValue {
484+
public:
485+
UnicodeString formatToString(UErrorCode&) const override;
486+
FixedDateValue();
487+
virtual ~FixedDateValue();
488+
private:
489+
friend class FixedDateFunction;
490+
491+
UnicodeString formattedString;
492+
FixedDateValue(const FunctionValue&, const FunctionOptions&, UErrorCode&);
493+
};
494+
495+
UnicodeString FixedDateValue::formatToString(UErrorCode& status) const {
496+
(void) status;
497+
// This is a test class, it just outputs a silly fixed value.
498+
return u"A Day ending in Y";
499+
}
500+
FixedDateValue::~FixedDateValue() {}
501+
502+
FixedDateValue::FixedDateValue(const FunctionValue& arg,
503+
const FunctionOptions& options,
504+
UErrorCode& errorCode) {
505+
(void)arg;
506+
(void)options;
507+
if (U_FAILURE(errorCode)) {
508+
return;
509+
}
510+
511+
// no input, no options
512+
}
513+
514+
class FixedDateFunction : public Function {
515+
public:
516+
FixedDateFunction(UErrorCode& status);
517+
LocalPointer<FunctionValue> call(const FunctionContext &, const FunctionValue &,
518+
const FunctionOptions &, UErrorCode &) override;
519+
virtual ~FixedDateFunction();
520+
};
521+
522+
FixedDateFunction::FixedDateFunction(UErrorCode& status) {
523+
(void)status;
524+
}
525+
526+
LocalPointer<FunctionValue> FixedDateFunction::call(const FunctionContext &context,
527+
const FunctionValue &arg,
528+
const FunctionOptions &opts,
529+
UErrorCode &errorCode) {
530+
(void)context;
531+
532+
if (U_FAILURE(errorCode)) {
533+
return LocalPointer<FunctionValue>();
534+
}
535+
LocalPointer<FunctionValue> v(new FixedDateValue(arg, std::move(opts), errorCode));
536+
return v;
537+
}
538+
539+
FixedDateFunction::~FixedDateFunction() {}
540+
541+
void TestMessageFormat2::testOverrideFunctions() {
542+
IcuTestErrorCode errorCode(*this, "testOverrideFunctions");
543+
UParseError parseError;
544+
545+
std::map<UnicodeString, icu::message2::Formattable> argsBuilder;
546+
argsBuilder["count"] = message2::Formattable((int64_t)13);
547+
argsBuilder["name"] = message2::Formattable("US");
548+
argsBuilder["birthday"] = message2::Formattable("1776-07-04");
549+
icu::message2::MessageArguments args(argsBuilder, errorCode);
550+
UnicodeString expectedResult(u"PASS 13 @ \u2068A Day ending in Y\u2069");
551+
552+
const UnicodeString orig_pattern(
553+
u""
554+
".input {$count :number} .input {$name :string} .input {$birthday :date}\n"
555+
".match $count\n"
556+
"many {{PASS {$count} @ {$birthday :date style=short}}}\n"
557+
"* {{FAIL wrong bucket {$count} @ {$birthday :date style=short}}}\n");
558+
559+
{
560+
// build the function registry
561+
icu::message2::MFFunctionRegistry::Builder builder(errorCode);
562+
MFFunctionRegistry functionRegistry =
563+
builder
564+
.adoptFunction(data_model::FunctionName("date"), // override
565+
new FixedDateFunction(errorCode), errorCode)
566+
.build();
567+
568+
icu::message2::MessageFormatter mf =
569+
MessageFormatter::Builder(errorCode)
570+
.setErrorHandlingBehavior(MessageFormatter::U_MF_BEST_EFFORT)
571+
.setPattern(orig_pattern, parseError, errorCode)
572+
.setFunctionRegistry(functionRegistry)
573+
.setLocale(Locale("pl"))
574+
.build(errorCode);
575+
576+
if (errorCode.errIfFailureAndReset("build")) {
577+
errln("UParseError = %d:%d", parseError.line, parseError.offset);
578+
return;
579+
}
580+
581+
UnicodeString result = mf.formatToString(args, errorCode);
582+
if (errorCode.errIfFailureAndReset("formatToString")) {
583+
return;
584+
}
585+
assertEquals("testSetFormatLocale", expectedResult, result);
586+
}
587+
}
588+
482589
TestCase::~TestCase() {}
483590
TestCase::Builder::~Builder() {}
484591

icu4c/source/test/intltest/messageformat2test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class TestMessageFormat2: public IntlTest {
5353
void testBidiAPI(void);
5454
void testAPI(void);
5555
void testAPISimple(void);
56+
void testOverrideFunctions(void);
5657

5758
private:
5859
void jsonTestsFromFiles(IcuTestErrorCode&);

0 commit comments

Comments
 (0)