Skip to content

[mustache_template] Fix auto-generated specification tests, run with dart test#11056

Open
jslater89 wants to merge 18 commits intoflutter:mainfrom
jslater89:spec-test-runner
Open

[mustache_template] Fix auto-generated specification tests, run with dart test#11056
jslater89 wants to merge 18 commits intoflutter:mainfrom
jslater89:spec-test-runner

Conversation

@jslater89
Copy link
Copy Markdown

This PR reorganizes the tests in mustache_template such that CI can run them, per the second option proposed in flutter/flutter#174721. The changes include a script to pull mustache specifications from the mustache repository and note the time/date and commit hash of that action, along with documentation of the above and the new test structure laid out below.

The former all.dart (which called three main functions in three test files) is now mustache_test.dart, and the former mustache_test.dart (which contained handwritten tests) is now feature_test.dart. The mustache_specs.dart file is now solely responsible for generating the tests in mustache_test.dart from the mustache specs, and no longer has a main of its own.

As this implementation doesn't support two of the optional mustache specs (inheritance and dynamic names, which were added to the mustache repo in the early 2020s, while the original mustache_template package was written in the mid-2010s), this PR also adds an UNSUPPORTED_SPECS constant in mustache_test.dart that skips generation of tests from those spec files.

(Separately, I'm working on an implementation of the inheritance spec, so it seemed better to pull all the specification files and selectively disable the unsupported ones.)

Pre-Review Checklist

Exemptions

  • Version change exemption: PR affects tests only.
  • CHANGELOG exemption: PR affects tests only.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a significant and valuable refactoring of the mustache_template test suite. By reorganizing the tests to be runnable with dart test, introducing a script to manage the mustache specifications, and cleaning up the test structure, you've greatly improved the maintainability and usability of the tests. The changes are well-documented in the new README.md. I have a couple of suggestions to further improve the new download script and enhance consistency within the test code.

Comment on lines +1 to +15
git clone https://github.com/mustache/spec.git tmp_spec

HEAD_HASH=$(git -C tmp_spec rev-parse HEAD)
UTC_NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)

if [ -d "specs" ]; then
rm -rf specs
fi
mkdir -p specs

mv tmp_spec/specs/* specs/
rm -rf tmp_spec

echo "Specs commit: $HEAD_HASH" > specs/meta.txt
echo "Specs download date: $UTC_NOW" >> specs/meta.txt
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This script is a great addition for managing the spec files. To make it more robust and slightly simpler, I suggest adding a shebang and set -e at the top. The shebang ensures the script is run with the correct interpreter, and set -e will cause the script to exit immediately if any command fails, preventing potential issues.

I've also simplified the directory removal logic, as rm -rf doesn't error if the directory doesn't exist, making the if check redundant.

Suggested change
git clone https://github.com/mustache/spec.git tmp_spec
HEAD_HASH=$(git -C tmp_spec rev-parse HEAD)
UTC_NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
if [ -d "specs" ]; then
rm -rf specs
fi
mkdir -p specs
mv tmp_spec/specs/* specs/
rm -rf tmp_spec
echo "Specs commit: $HEAD_HASH" > specs/meta.txt
echo "Specs download date: $UTC_NOW" >> specs/meta.txt
#!/bin/bash
set -e
git clone https://github.com/mustache/spec.git tmp_spec
HEAD_HASH=$(git -C tmp_spec rev-parse HEAD)
UTC_NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
rm -rf specs
mkdir -p specs
mv tmp_spec/specs/* specs/
rm -rf tmp_spec
echo "Specs commit: $HEAD_HASH" > specs/meta.txt
echo "Specs download date: $UTC_NOW" >> specs/meta.txt

Comment on lines +316 to +320
expect(ex is TemplateException, isTrue);
expect(
(ex! as TemplateException).message,
startsWith(BAD_VALUE_INV_SECTION),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For consistency with other tests in this file (e.g., 'Mismatched tag' on line 396), you can use the existing expectFail helper function here. This will make the test more concise and readable by abstracting the exception checking logic.

Suggested change
expect(ex is TemplateException, isTrue);
expect(
(ex! as TemplateException).message,
startsWith(BAD_VALUE_INV_SECTION),
);
expectFail(ex, null, null, BAD_VALUE_INV_SECTION);

@stuartmorgan-g
Copy link
Copy Markdown
Collaborator

  • All existing and new tests are passing.

While waiting for review, FYI unit tests are failing in CI on several platforms, which will need to be addressed.

@jslater89
Copy link
Copy Markdown
Author

Whoops, so they are.

The web tests are failing because the specification test generator relies on dart:io; that would have been broken before too. I'll still fix that if needed.

The Windows failure is probably me being a dope about path separators.

I'll correct the formatting issues too when I do the others, some night this week.

@stuartmorgan-g
Copy link
Copy Markdown
Collaborator

The web tests are failing because the specification test generator relies on dart:io; that would have been broken before too.

Except that the stated purpose of the PR is:

This PR reorganizes the tests in mustache_template such that CI can run them

If something wasn't run in CI before, then it wasn't broken in CI before.

I'll still fix that if needed.

I'm not sure what you mean by "if needed". Isn't the goal to land the PR? We can't land a PR that breaks CI.

The handwritten 'null inverted section' test expected no output from
{{^section}} content {{/section}} when {'section': null} in the context,
but specs/inverted/Null is falsey indicates that the content should
render in that case.
Lenient mode allows almost everything, but not empty tag names.
{{>}} is an empty tag name: it asks for a partial with the name
'empty string'. All tags whose contents begin with a tag type
sigil should be parsed as a tag of that type.

{{ a> }} is a valid tag name and passes a new test. Tests are also
included for empty tag names of all types.
@jslater89 jslater89 requested a review from bkonyi February 25, 2026 16:20
@jslater89
Copy link
Copy Markdown
Author

Since the last review:

  1. All tests passing on all platforms. The download-specs script now generates Dart files that contain strings containing the JSON specification files, so there's no dart:io dependency in the tests anymore.
  2. Expects-exception tests refactored to use throwsA.
  3. Tests commented out during the original library import reviewed, along with TODOs in tests. Some were edited:
    • feature_test.dart@258: {{ > }} is not a valid tag even in lenient mode: it's an open-partial tag with an empty name, and empty names are invalid in both modes. On the other hand, {{ a> }} is a valid name in lenient mode—identifiers can include characters that would scan as sigil tokens, but the open-delimiter sigil sequence always opens a tag.
    • feature_test.dart@503: the commented test labeled 'known failure' conflicted with one of the Mustache spec tests (null is falsey and should cause an inverted section to render), so it was removed.
    • 'should fail with exception' tests refactored to use throwsA.

Copy link
Copy Markdown
Contributor

@bkonyi bkonyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of comments, but this mostly looks good.

This will need a minor version bump in the pubspec.yaml, a corresponding CHANGELOG.md entry, and feature_test.dart needs to be formatted.

_defineGroupFromFile(filename, text);
}
void defineTests(List<String> unsupportedSpecs) {
for (final MapEntry<String, String> entry in SPECS.entries) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this could use object destructuring instead

for (final MapEntry(key: specName, value: text) in SPECS.entries) {
  // ...
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You know, I'd forgotten that was a context where patterns work.

Resolved in 168e220.

@@ -0,0 +1,106 @@
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need all of the JSON, Dart, and YAML files for each of these?

Since we're only consuming the *.dart files, we probably don't need to commit the original *.json and *.yml files pulled from the repo. Can we add them to the .gitignore?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point!

Since the download script puts them in a temporary directory anyway, I just kept the Dart files only in b0363cf.

@stuartmorgan-g
Copy link
Copy Markdown
Collaborator

This will need a minor version bump in the pubspec.yaml, a corresponding CHANGELOG.md entry

test/ changes don't need versions or changelogs by repo policy. The failure is just a false positive because we don't happen to have .gitignore on the allow-list of known exempt files.

@stuartmorgan-g stuartmorgan-g added override: no versioning needed Override the check requiring version bumps for most changes override: no changelog needed Override the check requiring CHANGELOG updates for most changes labels Mar 4, 2026
@bkonyi
Copy link
Copy Markdown
Contributor

bkonyi commented Mar 4, 2026

This will need a minor version bump in the pubspec.yaml, a corresponding CHANGELOG.md entry

test/ changes don't need versions or changelogs by repo policy. The failure is just a false positive because we don't happen to have .gitignore on the allow-list of known exempt files.

Ah makes sense, thanks for clarifying! Good to know those labels are there for the future.

@jslater89
Copy link
Copy Markdown
Author

Whoops, the commits I mentioned in the comments above were in my inheritance feature branch. They're in this PR now.

@jslater89 jslater89 requested a review from bkonyi March 9, 2026 19:59
Copy link
Copy Markdown
Contributor

@bkonyi bkonyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Mar 16, 2026
@auto-submit auto-submit bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Mar 16, 2026
@auto-submit
Copy link
Copy Markdown
Contributor

auto-submit bot commented Mar 16, 2026

autosubmit label was removed for flutter/packages/11056, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a flutter-hacker before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

Copy link
Copy Markdown
Member

@parlough parlough left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing and documenting this test setup. Looks good to me, with some minor suggestions to consider:

@jslater89
Copy link
Copy Markdown
Author

Sorry for the long delay; work got busy. I rewrote the shell script as a Dart script, and made the style changes from @parlough's review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

override: no changelog needed Override the check requiring CHANGELOG updates for most changes override: no versioning needed Override the check requiring version bumps for most changes p: mustache_template

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants