Skip to content

Commit

Permalink
ICU-22794 MF2: Move .json files for tests into top-level testdata/ di…
Browse files Browse the repository at this point in the history
…rectory

Modify ICU4C and ICU4J test readers to handle all tests

Add `ignoreJava` and `ignoreCpp` properties to tests where needed

Includes parser bug fixes:

ICU4J: require a complex-body after declarations

ICU4J: Correctly parse the complex body after an unsupported statement

ICU4J: Handle date params in tests and remove default params for tests

ICU4J: Handle decimal params in tests

ICU4J: Require whitespace before variable/literal in reserved annotation

ICU4J: Require whitespace between options

ICU4J: Require a variable-expression in an .input declaration

ICU4J: don't require space between last key and pattern in variant

ICU4J: don't require space between selectors

ICU4J: allow whitespace after '=' in option

ICU4J: parse escape sequences in quoted literals according to grammar

ICU4J: allow whitespace within markup after attributes list
  • Loading branch information
catamorphism authored and echeran committed Aug 8, 2024
1 parent 366bb46 commit 57ed0a2
Show file tree
Hide file tree
Showing 53 changed files with 1,119 additions and 1,444 deletions.
2 changes: 2 additions & 0 deletions icu4c/source/config/dist.mk
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ $(DISTY_FILE_TGZ) $(DISTY_FILE_ZIP) $(DISTY_DATA_ZIP): $(DISTY_DAT) $(DISTY_TMP
( cd $(ICU4CTOP)/.. && git archive --format=tar --prefix=icu/ HEAD:icu4c/ ) | ( cd "$(DISTY_TMP)" && tar xf - )
# special handling for LICENSE file. The symlinks will be included as files by tar and zip.
cp -fv $(ICU4CTOP)/LICENSE "$(DISTY_TMP)/LICENSE"
# Copy top-level testdata directory so it's a sibling of the source/ directory
cp -R $(ICU4CTOP)/../testdata $(DISTY_TMP)/icu
( cd $(DISTY_TMP)/icu/source ; zip -rlq $(DISTY_DATA_ZIP) data )
$(MKINSTALLDIRS) $(DISTY_IN)
echo DISTY_DAT=$(DISTY_DAT)
Expand Down
55 changes: 55 additions & 0 deletions icu4c/source/test/intltest/intltest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,61 @@ const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
return srcDataDir;
}

static bool fileExists(const char* fileName) {
// Test for `srcDataDir` existing by checking for `srcDataDir`/message2/valid-tests.json
U_ASSERT(fileName != nullptr);
FILE *f = fopen(fileName, "r");
if (f) {
fclose(f);
return true;
}
return false;
}

/**
* Returns the path to icu/testdata/
*/
const char *IntlTest::getSharedTestData(UErrorCode& err) {
#define SOURCE_TARBALL_TOP U_TOPSRCDIR U_FILE_SEP_STRING ".." U_FILE_SEP_STRING
#define REPO_TOP SOURCE_TARBALL_TOP ".." U_FILE_SEP_STRING
#define FILE_NAME U_FILE_SEP_STRING "message2" U_FILE_SEP_STRING "valid-tests.json"
const char *srcDataDir = nullptr;
const char *testFile = nullptr;
if (U_SUCCESS(err)) {
#ifdef U_TOPSRCDIR
// Try U_TOPSRCDIR/../testdata (source tarball)
srcDataDir = SOURCE_TARBALL_TOP "testdata" U_FILE_SEP_STRING;
testFile = SOURCE_TARBALL_TOP "testdata" FILE_NAME;
if (!fileExists(testFile)) {
// If that doesn't exist, try U_TOPSRCDIR/../../testdata (in-repo)
srcDataDir = REPO_TOP "testdata" U_FILE_SEP_STRING;
testFile = REPO_TOP "testdata" FILE_NAME;
if (!fileExists(testFile)) {
// If neither exists, return null
err = U_FILE_ACCESS_ERROR;
srcDataDir = nullptr;
}
}
#else
// Try ../../../../testdata (if we're in icu/source/test/intltest)
// and ../../../../../../testdata (if we're in icu/source/test/intltest/Platform/(Debug|Release)
#define TOP ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING
#define TOP_TOP ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING TOP
srcDataDir = TOP "testdata" U_FILE_SEP_STRING;
testFile = TOP "testdata" FILE_NAME;
if (!fileExists(testFile)) {
srcDataDir = TOP_TOP "testdata" U_FILE_SEP_STRING;
testFile = TOP_TOP "testdata" FILE_NAME;
if (!fileExists(testFile)) {
err = U_FILE_ACCESS_ERROR;
srcDataDir = nullptr;
}
}
#endif
}
return srcDataDir;
}

char *IntlTest::getUnidataPath(char path[]) {
const int kUnicodeDataTxtLength = 15; // strlen("UnicodeData.txt")

Expand Down
2 changes: 2 additions & 0 deletions icu4c/source/test/intltest/intltest.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,8 @@ class IntlTest : public TestLog {
static const char* loadTestData(UErrorCode& err);
virtual const char* getTestDataPath(UErrorCode& err) override;
static const char* getSourceTestData(UErrorCode& err);
// Gets the path for the top-level testdata/ directory
static const char* getSharedTestData(UErrorCode& err);
static char *getUnidataPath(char path[]);
char16_t *ReadAndConvertFile(const char *fileName, int &ulen, const char *encoding, UErrorCode &status);

Expand Down
45 changes: 25 additions & 20 deletions icu4c/source/test/intltest/messageformat2test_read_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ static UErrorCode getExpectedErrorFromString(const std::string& errorName) {
}

static UErrorCode getExpectedRuntimeErrorFromString(const std::string& errorName) {
if (errorName == "unresolved-var") {
if (errorName == "parse-error" || errorName == "empty-token" || errorName == "extra-content") {
return U_MF_SYNTAX_ERROR;
}
if (errorName == "key-mismatch") {
return U_MF_VARIANT_KEY_MISMATCH_ERROR;
}
if (errorName == "missing-var" || errorName == "unresolved-var") {
return U_MF_UNRESOLVED_VARIABLE_ERROR;
}
if (errorName == "unsupported-annotation") {
Expand Down Expand Up @@ -137,7 +143,8 @@ static void runValidTest(TestMessageFormat2& icuTest,

// Certain ICU4J tests don't work yet in ICU4C.
// See ICU-22754
if (!j_object["ignoreTest"].is_null()) {
// ignoreCpp => only works in Java
if (!j_object["ignoreCpp"].is_null()) {
return;
}

Expand Down Expand Up @@ -210,7 +217,7 @@ static void runSyntaxErrorTest(TestMessageFormat2& icuTest,
static void runICU4JSyntaxTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string testFileName(testDataDirectory);
Expand Down Expand Up @@ -252,7 +259,7 @@ static void runICU4JSyntaxTestsFromJsonFile(TestMessageFormat2& t,
static void runICU4JSelectionTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string testFileName(testDataDirectory);
Expand All @@ -270,7 +277,7 @@ static void runICU4JSelectionTestsFromJsonFile(TestMessageFormat2& t,
auto variations = j_object["variations"];

// Skip ignored tests
if (!j_object["ignoreTest"].is_null()) {
if (!j_object["ignoreCpp"].is_null()) {
return;
}

Expand All @@ -281,7 +288,7 @@ static void runICU4JSelectionTestsFromJsonFile(TestMessageFormat2& t,
messageText += piece;
}

t.logln("ICU4J selectors tests:");
t.logln(u_str("ICU4J selectors tests: " + fileName));
t.logln(u_str(iter->dump()));

TestCase::Builder test;
Expand Down Expand Up @@ -315,7 +322,7 @@ static void runICU4JSelectionTestsFromJsonFile(TestMessageFormat2& t,
static void runValidTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string testFileName(testDataDirectory);
Expand All @@ -341,7 +348,7 @@ static void runValidTestsFromJsonFile(TestMessageFormat2& t,
static void runDataModelErrorTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string dataModelErrorsFileName(testDataDirectory);
Expand All @@ -368,7 +375,7 @@ static void runDataModelErrorTestsFromJsonFile(TestMessageFormat2& t,
for (auto messagesIter = messages.begin(); messagesIter != messages.end(); ++messagesIter) {
makeTestName(testName, sizeof(testName), errorName, testNum);
testBuilder.setName(testName);
t.logln(testName);
t.logln(u_str(fileName + ": " + testName));
testNum++;
UnicodeString messageText = u_str(*messagesIter);
t.logln(messageText);
Expand All @@ -386,7 +393,7 @@ static void runDataModelErrorTestsFromJsonFile(TestMessageFormat2& t,
static void runSyntaxErrorTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string syntaxErrorsFileName(testDataDirectory);
Expand Down Expand Up @@ -420,7 +427,7 @@ static void runSyntaxErrorTestsFromJsonFile(TestMessageFormat2& t,
static void runSyntaxTestsWithDiagnosticsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string testFileName(testDataDirectory);
Expand All @@ -446,7 +453,7 @@ static void runFunctionTestsFromJsonFile(TestMessageFormat2& t,
const std::string& fileName,
IcuTestErrorCode& errorCode) {
// Get the test data directory
const char* testDataDirectory = IntlTest::getSourceTestData(errorCode);
const char* testDataDirectory = IntlTest::getSharedTestData(errorCode);
CHECK_ERROR(errorCode);

std::string functionTestsFileName(testDataDirectory);
Expand All @@ -460,7 +467,7 @@ static void runFunctionTestsFromJsonFile(TestMessageFormat2& t,
for (auto iter = tests.begin(); iter != tests.end(); ++iter) {
int32_t testNum = 0;
auto functionName = iter->first;
t.logln("Function tests:");
t.logln(u_str("Function tests: " + fileName));
t.logln(u_str(iter->second.dump()));

// Array of tests
Expand All @@ -487,6 +494,7 @@ void TestMessageFormat2::jsonTestsFromFiles(IcuTestErrorCode& errorCode) {

// Do spec tests for syntax errors
runSyntaxErrorTestsFromJsonFile(*this, "spec/syntax-errors.json", errorCode);
runSyntaxErrorTestsFromJsonFile(*this, "more-syntax-errors.json", errorCode);

// Do tests for data model errors
runDataModelErrorTestsFromJsonFile(*this, "spec/data-model-errors.json", errorCode);
Expand Down Expand Up @@ -540,13 +548,10 @@ void TestMessageFormat2::jsonTestsFromFiles(IcuTestErrorCode& errorCode) {
runSyntaxTestsWithDiagnosticsFromJsonFile(*this, "syntax-errors-diagnostics-multiline.json", errorCode);

// ICU4J tests
runFunctionTestsFromJsonFile(*this, "icu4j/icu-test-functions.json", errorCode);
// Changes made to get these tests to work:
// * removed double backslashes from "Hello \\t \\n \\r \\{ world!"
// * added empty {{}} pattern at the end of the tests under "Simple messages, with declarations"
// and the first one under "Multiple declarations in one message"
runICU4JSyntaxTestsFromJsonFile(*this, "icu4j/icu-parser-tests.json", errorCode);
runICU4JSelectionTestsFromJsonFile(*this, "icu4j/icu-test-selectors.json", errorCode);
runFunctionTestsFromJsonFile(*this, "icu-test-functions.json", errorCode);
runICU4JSyntaxTestsFromJsonFile(*this, "icu-parser-tests.json", errorCode);
runICU4JSelectionTestsFromJsonFile(*this, "icu-test-selectors.json", errorCode);
runValidTestsFromJsonFile(*this, "icu-test-previous-release.json", errorCode);
}

#endif /* #if !UCONFIG_NO_MF2 */
Expand Down
40 changes: 0 additions & 40 deletions icu4c/source/test/testdata/message2/README.txt

This file was deleted.

10 changes: 0 additions & 10 deletions icu4c/source/test/testdata/message2/invalid-options.json

This file was deleted.

39 changes: 0 additions & 39 deletions icu4c/source/test/testdata/message2/reserved-syntax.json

This file was deleted.

8 changes: 0 additions & 8 deletions icu4c/source/test/testdata/message2/resolution-errors.json

This file was deleted.

Loading

0 comments on commit 57ed0a2

Please sign in to comment.