This is an archive of the discontinued LLVM Phabricator instance.

[lit] Add a method to lit.TestFormat to get the list of tests associated to a path
ClosedPublic

Authored by ldionne on May 29 2023, 2:01 PM.

Details

Summary

Lit TestFormat classes already needed to implement the getTestsInDirectory
method. However, some test formats may want to expand a single test path
to multiple Lit tests, for example in the case of a test that actually
generates other Lit tests.

To accommodate that, this commit adds the getTestsForFilename method to
TestFormat. This method can be used to turn a single path in a Lit test
suite into a list of tests associated to that path.

Diff Detail

Event Timeline

ldionne created this revision.May 29 2023, 2:01 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 29 2023, 2:01 PM
ldionne requested review of this revision.May 29 2023, 2:01 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptMay 29 2023, 2:01 PM
Herald added a reviewer: Restricted Project. · View Herald Transcript

For context, the problem this solves is that libc++ now has a special kind of test called .gen tests. Those tests are basically a script that generates other Lit tests on the fly. This means that if I run for example lit libcxx/test/libcxx/assertions/headers_declare_verbose_abort.gen.py, I need Lit to actually understand that this corresponds to more than one test, i.e. all the tests generated in that .gen.py file.

I think this abstraction is actually what we want most of the time instead of getTestsInDirectory -- indeed, I looked at several custom test formats and most seemed to define getTestsInDirectory in a way that defining getTestsForFilename would have worked better, and then getTestsInDirectory would have been implemented generically on top of that.

Friendly ping, it would be great when people more familiar with lit can review this. This would make it easy to run lit on the generated files.

yln accepted this revision.Jun 16 2023, 6:30 PM

Just a few question, change itself looks good!

LGTM, thanks!

llvm/utils/lit/lit/formats/base.py
9–16

Because of the method name getTestsForFilename this sounds like it should also be defined in FileBasedTest?! I am sure there is a reason you put into the TestFormat root class?

23

This is the default implementation, which is overridden in CxxStandardLibraryTest, right?

If I understand correctly, then existing TestFormats (even out of tree) ones should continue to work: if they override the old getTestsInDirectory, then they will continue to do their own thing (they will not know about/call into the new getTestsForFilename)!?

Should _getTestsForFilename be a "private" function (starting with`_`) of TestFormat? It can be overridden to customize test format/discovery , but the API that used by the LIT runner remains getTestsInDirectory!?

Just a few question, change itself looks good!

LGTM, thanks!

Thanks for the review!

ldionne added inline comments.Jun 21 2023, 12:31 PM
llvm/utils/lit/lit/formats/base.py
9–16

This needs to be defined in the TestFormat root class because llvm/utils/lit/lit/discovery.py needs to call it when it figures out all the tests in a TestSuite (in getTestsInSuite). This makes me think that getTestsForFilename might be the wrong name for this method. In a way, we're being passed a path_in_suite, which does not conceptually have to be a file name.

If we named this getTestsForPath, then we'd have:

class TestFormat(object):
  def getTestsForPath(self, testSuite, path_in_suite, litConfig, localConfig):
    yield lit.Test.Test(testSuite, path_in_suite, localConfig)

class FileBasedTest(TestFormat):
  def getTestsForPath(self, testSuite, path_in_suite, litConfig, localConfig):
    # Here we can assume paths are actual file names
    filename = path_in_suite[-1]

    # Ignore dot files and excluded tests.
    if filename.startswith(".") or filename in localConfig.excludes:
      return

    base, ext = os.path.splitext(filename)
    if ext in localConfig.suffixes:
      yield lit.Test.Test(testSuite, path_in_suite, localConfig)

  def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig):
    # Use getTestsForPath
    ...

WDYT?

23

This is the default implementation, which is overridden in CxxStandardLibraryTest, right?

Yes. See my suggestion in the other comment.

If I understand correctly, then existing TestFormats (even out of tree) ones should continue to work: if they override the old getTestsInDirectory, then they will continue to do their own thing (they will not know about/call into the new getTestsForFilename)!?

Yes, they would continue doing their own thing. However, it would be possible for some test formats to end up with implementations of getTestsInDirectory and getTestsForPath that are inconsistent, in case their getTestsInDirectory implementation tries to map one file name to multiple Lit tests but they haven't overridden getTestsForPath. I don't think this would break down given the usage of getTestsForPath we do today, however that would technically be incorrect and could break down if we started relying on getTestsForPath more as a source of truth.

Should _getTestsForFilename be a "private" function (starting with`_`) of TestFormat? It can be overridden to customize test format/discovery , but the API that used by the LIT runner remains getTestsInDirectory!?

I am not sure I understand what would be the intent of making this a private function, since it would be called from outside the class from getTestsInSuite. IMO it makes more sense for it to be public.

CC @bd1976llvm @thopre This is also related to D83069 and D94766. Specifically, after my patch, executing a test like

lit Inputs/standalone-tests/true.txt

using a config that doesn't mention .txt as a valid suffix would now result in the following warning:

lit.py: foo.py: warning: input 'Inputs/standalone-tests/true.txt' contained no tests

IMO this makes sense, and in fact I don't quite understand the motivation behind trying to allow running a test for which the config doesn't have a suffix configured. The original problem that D83069 was trying to solve remains solved after this patch, however: if you add a test with an invalid suffix and you try running it directly, Lit will not run it, it will complain that you're trying to run a path that "contains no tests". This seems to address the original issue that prompted D83069.

So I'd be inclined to basically remove the check that had been added by D83069 and the --no-indirectly-run-check flag (reading the reviews, it seems like this was perceived kind of as a hack anyway), and then we'd want to understand whether the "standalone test" use case truly requires being able to run arbitrary extensions that are not in the configured suffixes.

ldionne updated this revision to Diff 533409.Jun 21 2023, 2:44 PM

Fix test issues, add test for the new feature and implement the changes suggested in the patch so far.

ldionne updated this revision to Diff 533562.Jun 22 2023, 4:56 AM

Fix tests.

ldionne accepted this revision as: Restricted Project.Jun 22 2023, 4:57 AM
This revision is now accepted and ready to land.Jun 22 2023, 4:57 AM
yln accepted this revision.Jun 27 2023, 10:05 AM