Skip to content

[native_toolchain_c] Use ProcessManager and FileSystem #3072

Closed

Description

@dcharkes

Most of the time on our CI is spent running integration tests for package:native_toolchain_c and package:hooks_runner. (#90 (comment))

While it is valuable to run integration tests on CI, it would be nice if locally we could distinguish between integration tests and unit tests.

We could write unit tests in a style like flutter tools where we mock the file system and process calls.

This is quite a lot of tedious work though.

Activity

  1. added
    contributions-welcomeContributions welcome to help resolve this (the resolution is expected to be clear from the issue)
    P3A lower priority bug or feature request
    on Feb 10, 2026
  2. Varadraj75 commented on Aug 7, 2026

    @Varadraj75
    Contributor

    Hi @dcharkes, is this one still up for grabs? I'd like to take it.

    Had a look at the package first. Process spawning already goes through runProcess in src/utils/run_process.dart (plus one Process.run in env_from_bat.dart), so wiring a ProcessManager in there is small. The real work is the File/Directory usage, spread across about a dozen files (cbuilder, compiler_resolver, tool_resolver, the toolchain resolvers).

    My plan: add package:file and package:process, default to LocalFileSystem and LocalProcessManager so behavior stays the same, then add flutter_tools style unit tests with MemoryFileSystem and a fake process manager that just check the compiler and linker invocations without running real toolchains. Since this is a lot of tedious work I'd rather do it in small PRs, the process seam first, then file system area by area.

    Two questions before I start:

    1. Should fileSystem and processManager be exposed on the public CBuilder/CLinker constructors or kept internal?
    2. package:process would be a new dependency here (hooks_runner already uses package:file). Any concern since these packages roll into the SDK?
  3. dcharkes commented on Aug 7, 2026

    @dcharkes
    CollaboratorAuthor
    1. Should fileSystem and processManager be exposed on the public CBuilder/CLinker constructors or kept internal?

    I think they should be exposed as optional params in the same place as Logger.

    1. package:process would be a new dependency here (hooks_runner already uses package:file). Any concern since these packages roll into the SDK?

    Not really a concern. Major version bumps could be a bit tricky, but many other packages are depending on it too already. We don't really use native_toolchain_c directly in Flutter and Dart SDK anyway, only in hooks. So actual breaking changes to the public API, if they were to happen, affect only the integration test projects in the Flutter and Dart SDK.

    Yes! Still up for grabs. 🚀

  4. Varadraj75 commented on Aug 8, 2026

    @Varadraj75
    Contributor

    Thanks! Starting with the process manager part then.

  5. Varadraj75 commented on Aug 13, 2026

    @Varadraj75
    Contributor

    Next up, the file system half. I mapped the dart:io usage and I'd split it the same way as the process manager work:

    1. Add a FileSystem to ToolResolvingContext defaulting to LocalFileSystem (the remaining TODO there), and convert tool_resolver.dart itself: the which lookup, the glob-based resolvers via Glob.listFileSystem, and the exists checks.
    2. The SDK resolvers (android_ndk, xcode, msvc) reading context.fileSystem.
    3. The build side: CBuilder/CLinker get a fileSystem param like processManager, covering the out dir creation, include listing, and the symbol file writes in linker_options.

    Public APIs all take Uri, so nothing user-facing changes. Starting with 1 unless you'd rather see it sliced differently. Should the integration/unit test directory reorganization come after these, or fold into them?

  6. dcharkes commented on Aug 13, 2026

    @dcharkes
    CollaboratorAuthor

    Public APIs all take Uri, so nothing user-facing changes.

    Exactly, that's on purpose! 👌

    Starting with 1 unless you'd rather see it sliced differently.

    So you are suggesting to split it up in multiple PRs and only have the final PR add the public API fileSystem parameter. That could work. But I'm also fine with a PR that combines everything into 1 if that's easier. Maybe that's easier to verify: you can write a unit test that mocks both the process manager and the file system and expect a bunch of process calls and file reads to see that it all works as expected.

    (And then we can follow up after that to separate the test suite in unit tests and integration tests, so that we get a lot of test coverage fast for the unit tests already.)

  7. Varadraj75 commented on Aug 14, 2026

    @Varadraj75
    Contributor

    Combined it is, that verification argument sold me. One PR: FileSystem on ToolResolvingContext plus a fileSystem param on the builders mirroring processManager, all dart:io file usage converted, and a unit test that fakes both seams and asserts the process invocations and file operations for a CBuilder run. Test suite split as the follow-up.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestcontributions-welcomeContributions welcome to help resolve this (the resolution is expected to be clear from the issue)package:native_toolchain_c

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions