[ffigen] Add common code path for test configs (#491)

* Add common code path for test configs

* separate example configs from pubspec.yaml for testing

* share example configs with tests

* use chDir for native test

* Ensure local package paths work in tests

* regen + concurrency=1 to fix race conditions
diff --git a/pkgs/ffigen/.github/workflows/test-package.yml b/pkgs/ffigen/.github/workflows/test-package.yml
index e1c1ad0..8bcf6e6 100644
--- a/pkgs/ffigen/.github/workflows/test-package.yml
+++ b/pkgs/ffigen/.github/workflows/test-package.yml
@@ -52,7 +52,7 @@
       - name: Build test dylib and bindings
         run: dart test/setup.dart
       - name: Run VM tests
-        run: dart test --platform vm
+        run: dart test --platform vm --concurrency=1
 
   test-mac:
     needs: analyze
@@ -67,7 +67,7 @@
       - name: Build test dylib and bindings
         run: dart test/setup.dart
       - name: Run VM tests
-        run: dart test --platform vm
+        run: dart test --platform vm --concurrency=1
       - name: Collect coverage
         run: ./tool/coverage.sh
       - name: Upload coverage
@@ -89,7 +89,7 @@
       - name: Build test dylib and bindings
         run: dart test/setup.dart
       - name: Run VM tests
-        run: dart test --platform vm
+        run: dart test --platform vm --concurrency=1
 
   # Sanity check the latest `flutter create --template plugin_ffi`.
   # This will break if we change the Flutter template or the generated code.
diff --git a/pkgs/ffigen/example/c_json/README.md b/pkgs/ffigen/example/c_json/README.md
index 229d65b..f222cc2 100644
--- a/pkgs/ffigen/example/c_json/README.md
+++ b/pkgs/ffigen/example/c_json/README.md
@@ -15,7 +15,7 @@
 ## Generating bindings
 At the root of this example (`example/c_json`), run -
 ```
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 This will generate bindings in a file: [cjson_generated_bindings.dart](./cjson_generated_bindings.dart)
 
diff --git a/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart b/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
index 0571e62..c520c20 100644
--- a/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
+++ b/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
@@ -19,7 +19,6 @@
 // THE SOFTWARE.
 
 // ignore_for_file: camel_case_types, non_constant_identifier_names
-
 // AUTO GENERATED FILE, DO NOT EDIT.
 //
 // Generated by `package:ffigen`.
diff --git a/pkgs/ffigen/example/c_json/config.yaml b/pkgs/ffigen/example/c_json/config.yaml
new file mode 100644
index 0000000..08c5891
--- /dev/null
+++ b/pkgs/ffigen/example/c_json/config.yaml
@@ -0,0 +1,31 @@
+output: 'cjson_generated_bindings.dart'
+name: 'CJson'
+description: 'Holds bindings to cJSON.'
+headers:
+  entry-points:
+    - '../../third_party/cjson_library/cJSON.h'
+  include-directives:
+    - '**cJSON.h'
+comments: false
+preamble: |
+  // Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+  //
+  // Permission is hereby granted, free of charge, to any person obtaining a copy
+  // of this software and associated documentation files (the "Software"), to deal
+  // in the Software without restriction, including without limitation the rights
+  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  // copies of the Software, and to permit persons to whom the Software is
+  // furnished to do so, subject to the following conditions:
+  //
+  // The above copyright notice and this permission notice shall be included in
+  // all copies or substantial portions of the Software.
+  //
+  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  // THE SOFTWARE.
+
+  // ignore_for_file: camel_case_types, non_constant_identifier_names
\ No newline at end of file
diff --git a/pkgs/ffigen/example/c_json/pubspec.yaml b/pkgs/ffigen/example/c_json/pubspec.yaml
index 7b76a5c..1733b5f 100644
--- a/pkgs/ffigen/example/c_json/pubspec.yaml
+++ b/pkgs/ffigen/example/c_json/pubspec.yaml
@@ -15,36 +15,3 @@
   ffigen:
     path: '../../'
   lints: ^2.0.1
-
-ffigen:
-  output: 'cjson_generated_bindings.dart'
-  name: 'CJson'
-  description: 'Holds bindings to cJSON.'
-  headers:
-    entry-points:
-      - '../../third_party/cjson_library/cJSON.h'
-    include-directives:
-      - '**cJSON.h'
-  comments: false
-  preamble: |
-    // Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-    //
-    // Permission is hereby granted, free of charge, to any person obtaining a copy
-    // of this software and associated documentation files (the "Software"), to deal
-    // in the Software without restriction, including without limitation the rights
-    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-    // copies of the Software, and to permit persons to whom the Software is
-    // furnished to do so, subject to the following conditions:
-    //
-    // The above copyright notice and this permission notice shall be included in
-    // all copies or substantial portions of the Software.
-    //
-    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-    // THE SOFTWARE.
-
-    // ignore_for_file: camel_case_types, non_constant_identifier_names
diff --git a/pkgs/ffigen/example/ffinative/README.md b/pkgs/ffigen/example/ffinative/README.md
index c146940..82b0e88 100644
--- a/pkgs/ffigen/example/ffinative/README.md
+++ b/pkgs/ffigen/example/ffinative/README.md
@@ -5,6 +5,6 @@
 ## Generating bindings
 At the root of this example (`example/simple`), run -
 ```
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 This will generate bindings in a file: [generated_bindings.dart](./generated_bindings.dart).
diff --git a/pkgs/ffigen/example/ffinative/config.yaml b/pkgs/ffigen/example/ffinative/config.yaml
new file mode 100644
index 0000000..18aeb3f
--- /dev/null
+++ b/pkgs/ffigen/example/ffinative/config.yaml
@@ -0,0 +1,10 @@
+name: NativeLibrary
+ffi-native:
+  # asset: 'assetname' # (optional)
+description: Bindings to `headers/example.h`.
+output: 'generated_bindings.dart'
+headers:
+  entry-points:
+    - 'headers/example.h'
+preamble: |
+  // ignore_for_file: deprecated_member_use
\ No newline at end of file
diff --git a/pkgs/ffigen/example/ffinative/pubspec.yaml b/pkgs/ffigen/example/ffinative/pubspec.yaml
index 9747ec7..2247de4 100644
--- a/pkgs/ffigen/example/ffinative/pubspec.yaml
+++ b/pkgs/ffigen/example/ffinative/pubspec.yaml
@@ -13,15 +13,3 @@
   ffigen:
     path: '../../'
   lints: ^2.0.0
-
-ffigen:
-  name: NativeLibrary
-  ffi-native:
-    # asset: 'assetname' # (optional)
-  description: Bindings to `headers/example.h`.
-  output: 'generated_bindings.dart'
-  headers:
-    entry-points:
-      - 'headers/example.h'
-  preamble: |
-    // ignore_for_file: deprecated_member_use
diff --git a/pkgs/ffigen/example/libclang-example/config.yaml b/pkgs/ffigen/example/libclang-example/config.yaml
new file mode 100644
index 0000000..f6517c0
--- /dev/null
+++ b/pkgs/ffigen/example/libclang-example/config.yaml
@@ -0,0 +1,74 @@
+output: 'generated_bindings.dart'
+
+# This will sort the bindings alphabetically.
+# sort: true
+
+# This is required if LLVM can't be found in default locations by ffigen.
+# llvm-path:
+#   - '/usr/local/opt/llvm'
+
+# Bash style Glob matching is also supported.
+# TODO(11): Globs dont work on windows if they begin with '.' or '..'.
+headers:
+  entry-points:
+    - ../../third_party/libclang/include/clang-c/Index.h
+  include-directives: # use glob syntax to match with header file path.
+    - '**CXString.h'
+    - '**Index.h'
+
+compiler-opts:
+  - '-I../../third_party/libclang/include'
+  - '-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/'
+  - '-Wno-nullability-completeness'
+functions:
+  include:
+    - 'clang_.*' # Can be a regexp, '.' matches any character.
+  symbol-address:
+    include:
+      - 'clang_.*' # Symbol Address for these functions will be exposed via addresses.
+  expose-typedefs:
+    include:
+      - 'clang_.*' # Typedefs for Native and Dart type for these functions will be generated.
+structs:
+  include:
+      - 'CX.*'
+enums:
+  include:
+    - 'CXTypeKind' # Full names are given higher priority than regexp.
+    - 'CXGlobalOptFlags'
+
+library-imports:
+  custom_import: 'custom_import.dart'
+
+# These can be used to map any typedef to a specific native type.
+type-map:
+  typedefs:
+    'time_t':
+      lib: 'ffi'
+      c-type: 'Int64'
+      dart-type: 'int'
+  structs:
+    'CXCursorSetImpl':
+      lib: 'custom_import'
+      c-type: 'CXCursorSetImpl'
+      dart-type: 'CXCursorSetImpl'
+
+# Default is 'NativeLibrary'
+name: 'LibClang'
+
+description: 'Holds bindings to LibClang.'
+
+# Doc Comments for generated binings.
+# Comments can be disabled by using comments: false
+comments:
+  style: doxygen # Options - doxygen(default) / any.
+  length: full # Options - brief / full(default).
+
+# The header of the file, this is pasted as it is.
+preamble: |
+  // Part of the LLVM Project, under the Apache License v2.0 with LLVM
+  // Exceptions.
+  // See https://llvm.org/LICENSE.txt for license information.
+  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+  // ignore_for_file: camel_case_types, non_constant_identifier_names
diff --git a/pkgs/ffigen/example/libclang-example/pubspec.yaml b/pkgs/ffigen/example/libclang-example/pubspec.yaml
index bff5a3c..daef35b 100644
--- a/pkgs/ffigen/example/libclang-example/pubspec.yaml
+++ b/pkgs/ffigen/example/libclang-example/pubspec.yaml
@@ -13,78 +13,3 @@
   ffigen:
     path: '../../'
   lints: ^2.0.1
-
-ffigen:
-  output: 'generated_bindings.dart'
-
-  # This will sort the bindings alphabetically.
-  # sort: true
-
-  # This is required if LLVM can't be found in default locations by ffigen.
-  # llvm-path:
-  #   - '/usr/local/opt/llvm'
-
-  # Bash style Glob matching is also supported.
-  # TODO(11): Globs dont work on windows if they begin with '.' or '..'.
-  headers:
-    entry-points:
-      - ../../third_party/libclang/include/clang-c/Index.h
-    include-directives: # use glob syntax to match with header file path.
-      - '**CXString.h'
-      - '**Index.h'
-
-  compiler-opts:
-    - '-I../../third_party/libclang/include'
-    - '-Wno-nullability-completeness'
-  functions:
-    include:
-      - 'clang_.*' # Can be a regexp, '.' matches any character.
-    symbol-address:
-      include:
-        - 'clang_.*' # Symbol Address for these functions will be exposed via addresses.
-    expose-typedefs:
-      include:
-        - 'clang_.*' # Typedefs for Native and Dart type for these functions will be generated.
-  structs:
-    include:
-        - 'CX.*'
-  enums:
-    include:
-      - 'CXTypeKind' # Full names are given higher priority than regexp.
-      - 'CXGlobalOptFlags'
-
-  library-imports:
-    custom_import: 'custom_import.dart'
-
-  # These can be used to map any typedef to a specific native type.
-  type-map:
-    typedefs:
-      'time_t':
-        lib: 'ffi'
-        c-type: 'Int64'
-        dart-type: 'int'
-    structs:
-      'CXCursorSetImpl':
-        lib: 'custom_import'
-        c-type: 'CXCursorSetImpl'
-        dart-type: 'CXCursorSetImpl'
-
-  # Default is 'NativeLibrary'
-  name: 'LibClang'
-
-  description: 'Holds bindings to LibClang.'
-
-  # Doc Comments for generated binings.
-  # Comments can be disabled by using comments: false
-  comments:
-    style: doxygen # Options - doxygen(default) / any.
-    length: full # Options - brief / full(default).
-
-  # The header of the file, this is pasted as it is.
-  preamble: |
-    // Part of the LLVM Project, under the Apache License v2.0 with LLVM
-    // Exceptions.
-    // See https://llvm.org/LICENSE.txt for license information.
-    // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-    // ignore_for_file: camel_case_types, non_constant_identifier_names
diff --git a/pkgs/ffigen/example/libclang-example/readme.md b/pkgs/ffigen/example/libclang-example/readme.md
index dab0bdf..39f2474 100644
--- a/pkgs/ffigen/example/libclang-example/readme.md
+++ b/pkgs/ffigen/example/libclang-example/readme.md
@@ -6,6 +6,6 @@
 ## Generating bindings
 At the root of this example (`example/libclang-example`), run -
 ```
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 This will generate bindings in a file: [generated_bindings.dart](./generated_bindings.dart).
diff --git a/pkgs/ffigen/example/objective_c/README.md b/pkgs/ffigen/example/objective_c/README.md
index 1d62972..846b77a 100644
--- a/pkgs/ffigen/example/objective_c/README.md
+++ b/pkgs/ffigen/example/objective_c/README.md
@@ -38,7 +38,7 @@
 At the root of this example (`example/objective_c`), run:
 
 ```
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 
 This will generate [avf_audio_bindings.dart](./avf_audio_bindings.dart).
diff --git a/pkgs/ffigen/example/objective_c/config.yaml b/pkgs/ffigen/example/objective_c/config.yaml
new file mode 100644
index 0000000..94764ca
--- /dev/null
+++ b/pkgs/ffigen/example/objective_c/config.yaml
@@ -0,0 +1,13 @@
+name: AVFAudio
+description: Bindings for AVFAudio.
+language: objc
+output: 'avf_audio_bindings.dart'
+exclude-all-by-default: true
+objc-interfaces:
+  include:
+    - 'AVAudioPlayer'
+headers:
+  entry-points:
+    - '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AVFAudio.framework/Headers/AVAudioPlayer.h'
+preamble: |
+  // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api
diff --git a/pkgs/ffigen/example/objective_c/pubspec.yaml b/pkgs/ffigen/example/objective_c/pubspec.yaml
index ab1e395..33b0c31 100644
--- a/pkgs/ffigen/example/objective_c/pubspec.yaml
+++ b/pkgs/ffigen/example/objective_c/pubspec.yaml
@@ -13,18 +13,3 @@
   ffigen:
     path: '../../'
   lints: ^2.0.0
-
-ffigen:
-  name: AVFAudio
-  description: Bindings for AVFAudio.
-  language: objc
-  output: 'avf_audio_bindings.dart'
-  exclude-all-by-default: true
-  objc-interfaces:
-    include:
-      - 'AVAudioPlayer'
-  headers:
-    entry-points:
-      - '/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AVFAudio.framework/Headers/AVAudioPlayer.h'
-  preamble: |
-    // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_api
diff --git a/pkgs/ffigen/example/simple/README.md b/pkgs/ffigen/example/simple/README.md
index 026ae9f..81d9569 100644
--- a/pkgs/ffigen/example/simple/README.md
+++ b/pkgs/ffigen/example/simple/README.md
@@ -5,6 +5,6 @@
 ## Generating bindings
 At the root of this example (`example/simple`), run -
 ```
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 This will generate bindings in a file: [generated_bindings.dart](./generated_bindings.dart).
diff --git a/pkgs/ffigen/example/simple/config.yaml b/pkgs/ffigen/example/simple/config.yaml
new file mode 100644
index 0000000..82ed925
--- /dev/null
+++ b/pkgs/ffigen/example/simple/config.yaml
@@ -0,0 +1,6 @@
+name: NativeLibrary
+description: Bindings to `headers/example.h`.
+output: 'generated_bindings.dart'
+headers:
+  entry-points:
+    - 'headers/example.h'
\ No newline at end of file
diff --git a/pkgs/ffigen/example/simple/pubspec.yaml b/pkgs/ffigen/example/simple/pubspec.yaml
index 33b93eb..d59f53e 100644
--- a/pkgs/ffigen/example/simple/pubspec.yaml
+++ b/pkgs/ffigen/example/simple/pubspec.yaml
@@ -14,10 +14,3 @@
     path: '../../'
   lints: ^2.0.1
 
-ffigen:
-  name: NativeLibrary
-  description: Bindings to `headers/example.h`.
-  output: 'generated_bindings.dart'
-  headers:
-    entry-points:
-      - 'headers/example.h'
diff --git a/pkgs/ffigen/example/swift/README.md b/pkgs/ffigen/example/swift/README.md
index 05c1c34..d53778e 100644
--- a/pkgs/ffigen/example/swift/README.md
+++ b/pkgs/ffigen/example/swift/README.md
@@ -22,7 +22,7 @@
 any other header:
 
 ```shell
-dart run ffigen
+dart run ffigen --config config.yaml
 ```
 
 This will generate [swift_api_bindings.dart](./swift_api_bindings.dart),
diff --git a/pkgs/ffigen/example/swift/config.yaml b/pkgs/ffigen/example/swift/config.yaml
new file mode 100644
index 0000000..e1a8322
--- /dev/null
+++ b/pkgs/ffigen/example/swift/config.yaml
@@ -0,0 +1,19 @@
+name: SwiftLibrary
+description: Bindings for swift_api.
+language: objc
+output: 'swift_api_bindings.dart'
+exclude-all-by-default: true
+objc-interfaces:
+  include:
+    - 'SwiftClass'
+  module:
+    'SwiftClass': 'swift_module'
+headers:
+  entry-points:
+    - 'swift_api.h'
+preamble: |
+  // ignore_for_file: camel_case_types, non_constant_identifier_names
+  // ignore_for_file: unused_element, unused_field, return_of_invalid_type
+  // ignore_for_file: void_checks, annotate_overrides
+  // ignore_for_file: no_leading_underscores_for_local_identifiers
+  // ignore_for_file: library_private_types_in_public_api
\ No newline at end of file
diff --git a/pkgs/ffigen/example/swift/pubspec.yaml b/pkgs/ffigen/example/swift/pubspec.yaml
index 8bd5e71..d00ffa9 100644
--- a/pkgs/ffigen/example/swift/pubspec.yaml
+++ b/pkgs/ffigen/example/swift/pubspec.yaml
@@ -13,24 +13,3 @@
   ffigen:
     path: '../../'
   lints: ^2.0.0
-
-ffigen:
-  name: SwiftLibrary
-  description: Bindings for swift_api.
-  language: objc
-  output: 'swift_api_bindings.dart'
-  exclude-all-by-default: true
-  objc-interfaces:
-    include:
-      - 'SwiftClass'
-    module:
-      'SwiftClass': 'swift_module'
-  headers:
-    entry-points:
-      - 'swift_api.h'
-  preamble: |
-    // ignore_for_file: camel_case_types, non_constant_identifier_names
-    // ignore_for_file: unused_element, unused_field, return_of_invalid_type
-    // ignore_for_file: void_checks, annotate_overrides
-    // ignore_for_file: no_leading_underscores_for_local_identifiers
-    // ignore_for_file: library_private_types_in_public_api
diff --git a/pkgs/ffigen/example/swift/swift_api.h b/pkgs/ffigen/example/swift/swift_api.h
index 45e5010..0928c49 100644
--- a/pkgs/ffigen/example/swift/swift_api.h
+++ b/pkgs/ffigen/example/swift/swift_api.h
@@ -1,4 +1,4 @@
-// Generated by Apple Swift version 5.5.2 (swiftlang-1300.0.40.106 clang-1300.0.29.21)
+// Generated by Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
 #ifndef SWIFT_MODULE_SWIFT_H
 #define SWIFT_MODULE_SWIFT_H
 #pragma clang diagnostic push
@@ -21,11 +21,20 @@
 # include <swift/objc-prologue.h>
 #endif
 
+#pragma clang diagnostic ignored "-Wduplicate-method-match"
 #pragma clang diagnostic ignored "-Wauto-import"
+#if defined(__OBJC__)
 #include <Foundation/Foundation.h>
+#endif
+#if defined(__cplusplus)
+#include <cstdint>
+#include <cstddef>
+#include <cstdbool>
+#else
 #include <stdint.h>
 #include <stddef.h>
 #include <stdbool.h>
+#endif
 
 #if !defined(SWIFT_TYPEDEFS)
 # define SWIFT_TYPEDEFS 1
@@ -181,9 +190,40 @@
 #else
 # define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
 #endif
+#if defined(__OBJC__)
 #if !defined(IBSegueAction)
 # define IBSegueAction
 #endif
+#endif
+#if !defined(SWIFT_EXTERN)
+# if defined(__cplusplus)
+#  define SWIFT_EXTERN extern "C"
+# else
+#  define SWIFT_EXTERN extern
+# endif
+#endif
+#if !defined(SWIFT_CALL)
+# define SWIFT_CALL __attribute__((swiftcall))
+#endif
+#if defined(__cplusplus)
+#if !defined(SWIFT_NOEXCEPT)
+# define SWIFT_NOEXCEPT noexcept
+#endif
+#else
+#if !defined(SWIFT_NOEXCEPT)
+# define SWIFT_NOEXCEPT 
+#endif
+#endif
+#if defined(__cplusplus)
+#if !defined(SWIFT_CXX_INT_DEFINED)
+#define SWIFT_CXX_INT_DEFINED
+namespace swift {
+using Int = ptrdiff_t;
+using UInt = size_t;
+}
+#endif
+#endif
+#if defined(__OBJC__)
 #if __has_feature(modules)
 #if __has_warning("-Watimport-in-framework-header")
 #pragma clang diagnostic ignored "-Watimport-in-framework-header"
@@ -191,6 +231,7 @@
 @import ObjectiveC;
 #endif
 
+#endif
 #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
 #pragma clang diagnostic ignored "-Wduplicate-method-arg"
 #if __has_warning("-Wpragma-clang-attribute")
@@ -198,6 +239,7 @@
 #endif
 #pragma clang diagnostic ignored "-Wunknown-pragmas"
 #pragma clang diagnostic ignored "-Wnullability"
+#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
 
 #if __has_attribute(external_source_symbol)
 # pragma push_macro("any")
@@ -206,8 +248,8 @@
 # pragma pop_macro("any")
 #endif
 
+#if defined(__OBJC__)
 @class NSString;
-@class NSNumber;
 
 SWIFT_CLASS("_TtC12swift_module10SwiftClass")
 @interface SwiftClass : NSObject
@@ -216,6 +258,9 @@
 - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
 @end
 
+#endif
+#if defined(__cplusplus)
+#endif
 #if __has_attribute(external_source_symbol)
 # pragma clang attribute pop
 #endif
diff --git a/pkgs/ffigen/lib/src/config_provider/config.dart b/pkgs/ffigen/lib/src/config_provider/config.dart
index 6290bac..e012e56 100644
--- a/pkgs/ffigen/lib/src/config_provider/config.dart
+++ b/pkgs/ffigen/lib/src/config_provider/config.dart
@@ -19,7 +19,7 @@
 
 /// Provides configurations to other modules.
 ///
-/// Handles validation, extraction of confiurations from yaml file.
+/// Handles validation, extraction of configurations from a yaml file.
 class Config {
   /// Input filename.
   String? get filename => _filename;
diff --git a/pkgs/ffigen/test/collision_tests/decl_type_name_collision_test.dart b/pkgs/ffigen/test/collision_tests/decl_type_name_collision_test.dart
index 40d9f88..19e9497 100644
--- a/pkgs/ffigen/test/collision_tests/decl_type_name_collision_test.dart
+++ b/pkgs/ffigen/test/collision_tests/decl_type_name_collision_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Decl type name collision test'
 ${strings.output}: 'unused'
@@ -27,7 +25,7 @@
     - 'test/collision_tests/decl_type_name_collision.h'
 ${strings.preamble}: |
     // ignore_for_file: non_constant_identifier_names, 
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/config_tests/compiler_opts_test.dart b/pkgs/ffigen/test/config_tests/compiler_opts_test.dart
index 5193d4d..0b711ac 100644
--- a/pkgs/ffigen/test/config_tests/compiler_opts_test.dart
+++ b/pkgs/ffigen/test/config_tests/compiler_opts_test.dart
@@ -6,7 +6,8 @@
 import 'package:ffigen/src/config_provider/spec_utils.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
+
+import '../test_utils.dart';
 
 late Library actual, expected;
 
@@ -28,7 +29,7 @@
       );
     });
     test('Compiler Opts Automatic', () {
-      final config = Config.fromYaml(yaml.loadYaml('''
+      final config = testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Compiler Opts Test'
 ${strings.output}: 'unused'
@@ -38,7 +39,7 @@
 ${strings.compilerOptsAuto}:
   ${strings.macos}:
     ${strings.includeCStdLib}: false
-        ''') as yaml.YamlMap);
+        ''');
       expect(config.compilerOpts.isEmpty, true);
     });
   });
diff --git a/pkgs/ffigen/test/config_tests/exclude_all_by_default_test.dart b/pkgs/ffigen/test/config_tests/exclude_all_by_default_test.dart
index 40bf1b2..361e4b2 100644
--- a/pkgs/ffigen/test/config_tests/exclude_all_by_default_test.dart
+++ b/pkgs/ffigen/test/config_tests/exclude_all_by_default_test.dart
@@ -6,14 +6,13 @@
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
 void main() {
   group('exclude_all_by_default', () {
     test('exclude_all_by_default test flag false', () {
-      final config = Config.fromYaml(yaml.loadYaml('''
+      final config = testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'exclude_all_by_default test'
 ${strings.output}: 'unused'
@@ -21,7 +20,7 @@
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/config_tests/exclude_all_by_default.h'
-''') as yaml.YamlMap);
+''');
 
       final library = parse(config);
       expect(library.getBinding('func'), isA<Func>());
@@ -34,7 +33,7 @@
     });
 
     test('exclude_all_by_default test flag true', () {
-      final config = Config.fromYaml(yaml.loadYaml('''
+      final config = testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'exclude_all_by_default test'
 ${strings.output}: 'unused'
@@ -42,7 +41,7 @@
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/config_tests/exclude_all_by_default.h'
-''') as yaml.YamlMap);
+''');
 
       final library = parse(config);
       expect(() => library.getBinding('func'), throwsException);
diff --git a/pkgs/ffigen/test/config_tests/include_exclude_test.dart b/pkgs/ffigen/test/config_tests/include_exclude_test.dart
index 5cc1156..1f27885 100644
--- a/pkgs/ffigen/test/config_tests/include_exclude_test.dart
+++ b/pkgs/ffigen/test/config_tests/include_exclude_test.dart
@@ -5,7 +5,6 @@
 import 'package:ffigen/ffigen.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -69,6 +68,6 @@
     }
   }
 
-  final config = Config.fromYaml(yaml.loadYaml(templateString) as yaml.YamlMap);
+  final config = testConfig(templateString);
   return config;
 }
diff --git a/pkgs/ffigen/test/config_tests/packed_struct_override_test.dart b/pkgs/ffigen/test/config_tests/packed_struct_override_test.dart
index cb0bf3c..68f8954 100644
--- a/pkgs/ffigen/test/config_tests/packed_struct_override_test.dart
+++ b/pkgs/ffigen/test/config_tests/packed_struct_override_test.dart
@@ -6,7 +6,6 @@
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -24,21 +23,15 @@
 ${strings.structs}:
   ${strings.structPack}:
     ''';
-      expect(
-          () => Config.fromYaml(
-              yaml.loadYaml("$baseYaml'.*': null") as yaml.YamlMap),
+      expect(() => testConfig("$baseYaml'.*': null"),
           throwsA(TypeMatcher<FormatException>()));
-      expect(
-          () => Config.fromYaml(
-              yaml.loadYaml("$baseYaml'.*': 3") as yaml.YamlMap),
+      expect(() => testConfig("$baseYaml'.*': 3"),
           throwsA(TypeMatcher<FormatException>()));
-      expect(
-          () => Config.fromYaml(
-              yaml.loadYaml("$baseYaml'.*': 32") as yaml.YamlMap),
+      expect(() => testConfig("$baseYaml'.*': 32"),
           throwsA(TypeMatcher<FormatException>()));
     });
     test('Override values', () {
-      final config = Config.fromYaml(yaml.loadYaml('''
+      final config = testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Packed Struct Override Test'
 ${strings.output}: 'unused'
@@ -50,7 +43,7 @@
     'Normal.*': 1
     'StructWithAttr': 2
     'PackedAttr': none
-        ''') as yaml.YamlMap);
+        ''');
 
       final library = parse(config);
 
diff --git a/pkgs/ffigen/test/config_tests/unknown_keys_warn_test.dart b/pkgs/ffigen/test/config_tests/unknown_keys_warn_test.dart
index 4fcb680..3dd0451 100644
--- a/pkgs/ffigen/test/config_tests/unknown_keys_warn_test.dart
+++ b/pkgs/ffigen/test/config_tests/unknown_keys_warn_test.dart
@@ -6,7 +6,6 @@
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +17,7 @@
     setUpAll(() {
       final logArr = <String>[];
       logWarningsToArray(logArr, Level.WARNING);
-      Config.fromYaml(yaml.loadYaml('''
+      testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Warn for unknown keys.'
 ${strings.output}: 'unused'
@@ -35,7 +34,7 @@
   'warn-5': 'skip'
 ${strings.unions}:
   'warn-6': 'skip'
-        ''') as yaml.YamlMap);
+        ''');
       logString = logArr.join("\n");
     });
     test('Warn for unknown keys.', () {
diff --git a/pkgs/ffigen/test/example_tests/cjson_example_test.dart b/pkgs/ffigen/test/example_tests/cjson_example_test.dart
index 4424615..714cb70 100644
--- a/pkgs/ffigen/test/example_tests/cjson_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/cjson_example_test.dart
@@ -2,12 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
-import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -17,45 +15,14 @@
       logWarnings(Level.SEVERE);
     });
     test('c_json', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.output}: 'cjson_generated_bindings.dart'
-${strings.name}: 'CJson'
-${strings.description}: 'Holds bindings to cJSON.'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - 'third_party/cjson_library/cJSON.h'
-  ${strings.includeDirectives}:
-    - '**cJSON.h'
-${strings.comments}: false
-${strings.preamble}: |
-  // Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
-  //
-  // Permission is hereby granted, free of charge, to any person obtaining a copy
-  // of this software and associated documentation files (the "Software"), to deal
-  // in the Software without restriction, including without limitation the rights
-  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-  // copies of the Software, and to permit persons to whom the Software is
-  // furnished to do so, subject to the following conditions:
-  //
-  // The above copyright notice and this permission notice shall be included in
-  // all copies or substantial portions of the Software.
-  //
-  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-  // THE SOFTWARE.
-
-  // ignore_for_file: camel_case_types, non_constant_identifier_names
-''') as YamlMap);
+      final config =
+          testConfigFromPath(path.join('example', 'c_json', 'config.yaml'));
       final library = parse(config);
 
       matchLibraryWithExpected(
         library,
         'example_c_json.dart',
-        ['example', 'c_json', config.output],
+        [config.output],
       );
     });
   });
diff --git a/pkgs/ffigen/test/example_tests/ffinative_example_test.dart b/pkgs/ffigen/test/example_tests/ffinative_example_test.dart
index 779b41a..28588b1 100644
--- a/pkgs/ffigen/test/example_tests/ffinative_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/ffinative_example_test.dart
@@ -2,12 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
-import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -18,23 +16,14 @@
     });
 
     test('ffinative', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.name}: NativeLibrary
-${strings.ffiNative}:
-${strings.description}: Bindings to `headers/example.h`.
-${strings.output}: 'generated_bindings.dart'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - 'example/ffinative/headers/example.h'
-${strings.preamble}: |
-  // ignore_for_file: deprecated_member_use
-''') as YamlMap);
+      final config =
+          testConfigFromPath(path.join('example', 'ffinative', 'config.yaml'));
       final library = parse(config);
 
       matchLibraryWithExpected(
         library,
         'example_ffinative.dart',
-        ['example', 'ffinative', config.output],
+        [config.output],
       );
     });
   });
diff --git a/pkgs/ffigen/test/example_tests/libclang_example_test.dart b/pkgs/ffigen/test/example_tests/libclang_example_test.dart
index c226c4c..8414e49 100644
--- a/pkgs/ffigen/test/example_tests/libclang_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/libclang_example_test.dart
@@ -2,12 +2,14 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:io';
+
+import 'package:ffigen/src/code_generator/library.dart';
 import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
-import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -17,65 +19,20 @@
       logWarnings(Level.SEVERE);
     });
     test('libclang-example', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.output}: 'generated_bindings.dart'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - third_party/libclang/include/clang-c/Index.h
-  ${strings.includeDirectives}:
-    - '**CXString.h'
-    - '**Index.h'
-
-${strings.compilerOpts}: '-Ithird_party/libclang/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -Wno-nullability-completeness'
-${strings.functions}:
-  ${strings.include}:
-    - 'clang_.*'
-  ${strings.symbolAddress}:
-      ${strings.include}:
-        - 'clang_.*'
-  ${strings.exposeFunctionTypedefs}:
-      ${strings.include}:
-        - 'clang_.*'
-${strings.structs}:
-  ${strings.include}:
-      - 'CX.*'
-${strings.enums}:
-  ${strings.include}:
-    - 'CXTypeKind'
-    - 'CXGlobalOptFlags'
-${strings.libraryImports}:
-  custom_import: 'custom_import.dart'
-${strings.typeMap}:
-  ${strings.typeMapTypedefs}:
-    'time_t':
-      lib: 'ffi'
-      c-type: 'Int64'
-      dart-type: 'int'
-  ${strings.typeMapStructs}:
-    'CXCursorSetImpl':
-      lib: 'custom_import'
-      c-type: 'CXCursorSetImpl'
-      dart-type: 'CXCursorSetImpl'
-${strings.name}: 'LibClang'
-${strings.description}: 'Holds bindings to LibClang.'
-${strings.comments}:
-  ${strings.style}: ${strings.doxygen}
-  ${strings.length}: ${strings.full}
-
-${strings.preamble}: |
-  // Part of the LLVM Project, under the Apache License v2.0 with LLVM
-  // Exceptions.
-  // See https://llvm.org/LICENSE.txt for license information.
-  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-  // ignore_for_file: camel_case_types, non_constant_identifier_names
-''') as YamlMap);
-      final library = parse(config);
+      final configYaml =
+          File(path.join('example', 'libclang-example', 'config.yaml'))
+              .absolute;
+      late Config config;
+      late Library library;
+      withChDir(configYaml.path, () {
+        config = testConfigFromPath(configYaml.path);
+        library = parse(config);
+      });
 
       matchLibraryWithExpected(
         library,
         'example_libclang.dart',
-        ['example', 'libclang-example', config.output],
+        [config.output],
       );
     });
   });
diff --git a/pkgs/ffigen/test/example_tests/objective_c_example_test.dart b/pkgs/ffigen/test/example_tests/objective_c_example_test.dart
index b53f341..b291edb 100644
--- a/pkgs/ffigen/test/example_tests/objective_c_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/objective_c_example_test.dart
@@ -5,13 +5,10 @@
 // Objective C support is only available on mac.
 @TestOn('mac-os')
 
-import 'dart:io';
-
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -22,9 +19,8 @@
     });
 
     test('objective_c', () {
-      final pubspecFile = File('example/objective_c/pubspec.yaml');
-      final pubspecYaml = loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
-      final config = Config.fromYaml(pubspecYaml['ffigen'] as YamlMap);
+      final config = testConfigFromPath(
+          path.join('example', 'objective_c', 'config.yaml'));
       final output = parse(config).generate();
 
       // Verify that the output contains all the methods and classes that the
diff --git a/pkgs/ffigen/test/example_tests/shared_bindings_example_test.dart b/pkgs/ffigen/test/example_tests/shared_bindings_example_test.dart
index 290ea40..0d4e39b 100644
--- a/pkgs/ffigen/test/example_tests/shared_bindings_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/shared_bindings_example_test.dart
@@ -2,12 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
-import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -18,48 +16,33 @@
     });
 
     test('a_shared_base bindings', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.name}: NativeLibraryASharedB
-${strings.description}: Bindings to `headers/a.h` with shared definitions from `headers/base.h`.
-${strings.output}: 'lib/generated/a_shared_b_gen.dart'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - 'example/shared_bindings/headers/a.h'
-${strings.import}:
-  ${strings.symbolFilesImport}:
-    - 'example/shared_bindings/lib/generated/base_symbols.yaml'
-${strings.preamble}: |
-  // ignore_for_file: non_constant_identifier_names, camel_case_types
-''') as YamlMap);
+      final config = testConfigFromPath(path.join(
+        'example',
+        'shared_bindings',
+        'ffigen_configs',
+        'a_shared_base.yaml',
+      ));
       final library = parse(config);
 
       matchLibraryWithExpected(
         library,
         'example_shared_bindings.dart',
-        ['example', 'shared_bindings', config.output],
+        [config.output],
       );
     });
 
     test('base symbol file output', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.name}: NativeLibraryBase
-${strings.description}: Bindings to `headers/base.h`.
-${strings.output}:
-  ${strings.bindings}: 'lib/generated/base_gen.dart'
-  ${strings.symbolFile}:
-    ${strings.output}: 'lib/generated/base_symbols.yaml'
-    ${strings.importPath}: 'package:shared_bindings/generated/base_gen.dart'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - 'example/shared_bindings/headers/base.h'
-${strings.preamble}: |
-  // ignore_for_file: non_constant_identifier_names, camel_case_types
-''') as YamlMap);
+      final config = testConfigFromPath(path.join(
+        'example',
+        'shared_bindings',
+        'ffigen_configs',
+        'base.yaml',
+      ));
       final library = parse(config);
       matchLibrarySymbolFileWithExpected(
         library,
         'example_shared_bindings.yaml',
-        ['example', 'shared_bindings', config.symbolFile!.output],
+        [config.symbolFile!.output],
         config.symbolFile!.importPath,
       );
     });
diff --git a/pkgs/ffigen/test/example_tests/simple_example_test.dart b/pkgs/ffigen/test/example_tests/simple_example_test.dart
index b79b576..343bf1c 100644
--- a/pkgs/ffigen/test/example_tests/simple_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/simple_example_test.dart
@@ -2,12 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
-import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -18,20 +16,17 @@
     });
 
     test('simple', () {
-      final config = Config.fromYaml(loadYaml('''
-${strings.name}: NativeLibrary
-${strings.description}: Bindings to `headers/example.h`.
-${strings.output}: 'generated_bindings.dart'
-${strings.headers}:
-  ${strings.entryPoints}:
-    - 'example/simple/headers/example.h'
-''') as YamlMap);
+      final config = testConfigFromPath(path.join(
+        'example',
+        'simple',
+        'config.yaml',
+      ));
       final library = parse(config);
 
       matchLibraryWithExpected(
         library,
         'example_simple.dart',
-        ['example', 'simple', config.output],
+        [config.output],
       );
     });
   });
diff --git a/pkgs/ffigen/test/example_tests/swift_example_test.dart b/pkgs/ffigen/test/example_tests/swift_example_test.dart
index 05c854c..02ed00a 100644
--- a/pkgs/ffigen/test/example_tests/swift_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/swift_example_test.dart
@@ -8,12 +8,10 @@
 import 'dart:async';
 import 'dart:io';
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
 import 'package:logging/logging.dart';
-import 'package:path/path.dart' as p;
+import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -38,16 +36,17 @@
             '-o',
             'libswiftapi.dylib',
           ],
-          workingDirectory: p.join(Directory.current.path, 'example/swift'));
+          workingDirectory: path.join(Directory.current.path, 'example/swift'));
       unawaited(stdout.addStream(process.stdout));
       unawaited(stderr.addStream(process.stderr));
       final result = await process.exitCode;
       expect(result, 0);
 
-      final pubspecFile = File('example/swift/pubspec.yaml');
-      final pubspecYaml = loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
-      final config = Config.fromYaml(pubspecYaml['ffigen'] as YamlMap,
-          filename: pubspecFile.path);
+      final config = testConfigFromPath(path.join(
+        'example',
+        'swift',
+        'config.yaml',
+      ));
       final output = parse(config).generate();
 
       // Verify that the output contains all the methods and classes that the
diff --git a/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart b/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart
index b7e5cfa..e31098a 100644
--- a/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/comment_markup_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Comment Markup Test'
 ${strings.output}: 'unused'
@@ -28,7 +26,7 @@
 ${strings.comments}:
   ${strings.style}: ${strings.any}
   ${strings.length}: ${strings.full}
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/dart_handle_test.dart b/pkgs/ffigen/test/header_parser_tests/dart_handle_test.dart
index dec4dec..484d8b0 100644
--- a/pkgs/ffigen/test/header_parser_tests/dart_handle_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/dart_handle_test.dart
@@ -4,12 +4,10 @@
 
 import 'package:cli_util/cli_util.dart';
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -20,7 +18,7 @@
     setUpAll(() {
       logWarnings();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Dart_Handle Test'
 ${strings.output}: 'unused'
@@ -31,7 +29,7 @@
     - 'test/header_parser_tests/dart_handle.h'
   ${strings.includeDirectives}:
     - '**dart_handle.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
     test('Expected Bindings', () {
diff --git a/pkgs/ffigen/test/header_parser_tests/forward_decl_test.dart b/pkgs/ffigen/test/header_parser_tests/forward_decl_test.dart
index f8f5894..73b9f32 100644
--- a/pkgs/ffigen/test/header_parser_tests/forward_decl_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/forward_decl_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,14 +16,14 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Forward Declaration Test'
 ${strings.output}: 'unused'
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/header_parser_tests/forward_decl.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart b/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
index 98dfafe..b61070c 100644
--- a/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/function_n_struct_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -20,7 +18,7 @@
       logWarnings(Level.SEVERE);
       expected = expectedLibrary();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Function And Struct Test'
 ${strings.output}: 'unused'
@@ -28,7 +26,7 @@
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/header_parser_tests/function_n_struct.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/functions_test.dart b/pkgs/ffigen/test/header_parser_tests/functions_test.dart
index b2718aa..97685b0 100644
--- a/pkgs/ffigen/test/header_parser_tests/functions_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/functions_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Functions Test'
 ${strings.output}: 'unused'
@@ -40,7 +38,7 @@
 
 ${strings.preamble}: |
   // ignore_for_file: camel_case_types
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
     test('Expected Bindings', () {
diff --git a/pkgs/ffigen/test/header_parser_tests/globals_test.dart b/pkgs/ffigen/test/header_parser_tests/globals_test.dart
index 1872ced..55184a8 100644
--- a/pkgs/ffigen/test/header_parser_tests/globals_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/globals_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -19,7 +17,7 @@
       logWarnings();
       expected = expectedLibrary();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Globals Test'
 ${strings.output}: 'unused'
@@ -37,7 +35,7 @@
       - pointerToLongDouble
       - globalStruct
 ${strings.compilerOpts}: '-Wno-nullability-completeness'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/imported_types_test.dart b/pkgs/ffigen/test/header_parser_tests/imported_types_test.dart
index 2d26c1f..fc02cff 100644
--- a/pkgs/ffigen/test/header_parser_tests/imported_types_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/imported_types_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Imported types test'
 ${strings.output}: 'unused'
@@ -31,7 +29,7 @@
 
 ${strings.preamble}: |
   // ignore_for_file: camel_case_types
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
     test('Expected Bindings', () {
diff --git a/pkgs/ffigen/test/header_parser_tests/macros_test.dart b/pkgs/ffigen/test/header_parser_tests/macros_test.dart
index 689a289..70439ef 100644
--- a/pkgs/ffigen/test/header_parser_tests/macros_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/macros_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -20,7 +18,7 @@
       logWarnings(Level.WARNING);
       expected = expectedLibrary();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Macros Test'
 ${strings.output}: 'unused'
@@ -29,7 +27,7 @@
     - 'test/header_parser_tests/macros.h'
   ${strings.includeDirectives}:
     - '**macros.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
     test('Total bindings count', () {
diff --git a/pkgs/ffigen/test/header_parser_tests/native_func_typedef_test.dart b/pkgs/ffigen/test/header_parser_tests/native_func_typedef_test.dart
index e576080..180ff4d 100644
--- a/pkgs/ffigen/test/header_parser_tests/native_func_typedef_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/native_func_typedef_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,14 +16,14 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Native Func Typedef Test.'
 ${strings.output}: 'unused'
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/header_parser_tests/native_func_typedef.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/nested_parsing_test.dart b/pkgs/ffigen/test/header_parser_tests/nested_parsing_test.dart
index 813c747..75803a0 100644
--- a/pkgs/ffigen/test/header_parser_tests/nested_parsing_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/nested_parsing_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -19,7 +17,7 @@
       logWarnings();
       expected = expectedLibrary();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Nested Parsing Test'
 ${strings.output}: 'unused'
@@ -29,7 +27,7 @@
 ${strings.structs}:
   ${strings.exclude}:
     - Struct2
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/opaque_dependencies_test.dart b/pkgs/ffigen/test/header_parser_tests/opaque_dependencies_test.dart
index c2572d5..fc73cfe 100644
--- a/pkgs/ffigen/test/header_parser_tests/opaque_dependencies_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/opaque_dependencies_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Opaque Dependencies Test'
 ${strings.output}: 'unused'
@@ -33,7 +31,7 @@
   ${strings.include}:
     - 'UE'
   ${strings.dependencyOnly}: ${strings.opaqueCompoundDependencies}
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
     test('Expected bindings', () {
diff --git a/pkgs/ffigen/test/header_parser_tests/packed_structs_test.dart b/pkgs/ffigen/test/header_parser_tests/packed_structs_test.dart
index bbd1ea7..62b7075 100644
--- a/pkgs/ffigen/test/header_parser_tests/packed_structs_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/packed_structs_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,14 +16,14 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Packed Structs Test'
 ${strings.output}: 'unused'
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/header_parser_tests/packed_structs.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/regress_384_test.dart b/pkgs/ffigen/test/header_parser_tests/regress_384_test.dart
index 054474c..b5751d1 100644
--- a/pkgs/ffigen/test/header_parser_tests/regress_384_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/regress_384_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Regression test for #384'
 ${strings.output}: 'unused'
@@ -26,7 +24,7 @@
   ${strings.entryPoints}:
     - 'test/header_parser_tests/regress_384_header_1.h'
     - 'test/header_parser_tests/regress_384_header_2.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/separate_definition_test.dart b/pkgs/ffigen/test/header_parser_tests/separate_definition_test.dart
index 6b62ade..663bebf 100644
--- a/pkgs/ffigen/test/header_parser_tests/separate_definition_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/separate_definition_test.dart
@@ -8,7 +8,6 @@
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -38,13 +37,13 @@
   for (final ep in entryPoints) {
     entryPointBuilder.writeln("    - $ep");
   }
-  final config = Config.fromYaml(yaml.loadYaml('''
+  final config = testConfig('''
 ${strings.name}: 'Bindings'
 ${strings.output}: 'unused'
 
 ${strings.headers}:
   ${strings.entryPoints}:
 ${entryPointBuilder.toString()}
-''') as yaml.YamlMap);
+''');
   return config;
 }
diff --git a/pkgs/ffigen/test/header_parser_tests/typedef_test.dart b/pkgs/ffigen/test/header_parser_tests/typedef_test.dart
index 0c75f30..51b90e6 100644
--- a/pkgs/ffigen/test/header_parser_tests/typedef_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/typedef_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -19,7 +17,7 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'Bindings'
 ${strings.output}: 'unused'
 
@@ -40,7 +38,7 @@
         dart-type: 'int'
 ${strings.preamble}: |
   // ignore_for_file: unused_element, unused_field
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/unions_test.dart b/pkgs/ffigen/test/header_parser_tests/unions_test.dart
index 8e8949e..e248dfb 100644
--- a/pkgs/ffigen/test/header_parser_tests/unions_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/unions_test.dart
@@ -3,12 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -18,14 +16,14 @@
     setUpAll(() {
       logWarnings(Level.SEVERE);
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Unions Test'
 ${strings.output}: 'unused'
 ${strings.headers}:
   ${strings.entryPoints}:
     - 'test/header_parser_tests/unions.h'
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/header_parser_tests/unnamed_enums_test.dart b/pkgs/ffigen/test/header_parser_tests/unnamed_enums_test.dart
index ea9f32d..eae9cf3 100644
--- a/pkgs/ffigen/test/header_parser_tests/unnamed_enums_test.dart
+++ b/pkgs/ffigen/test/header_parser_tests/unnamed_enums_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -19,7 +17,7 @@
       logWarnings();
       expected = expectedLibrary();
       actual = parser.parse(
-        Config.fromYaml(yaml.loadYaml('''
+        testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Unnamed Enums Test'
 ${strings.output}: 'unused'
@@ -32,7 +30,7 @@
 ${strings.unnamedEnums}:
   ${strings.exclude}:
     - B
-        ''') as yaml.YamlMap),
+        '''),
       );
     });
 
diff --git a/pkgs/ffigen/test/large_integration_tests/large_test.dart b/pkgs/ffigen/test/large_integration_tests/large_test.dart
index 77fe1ec..257ff26 100644
--- a/pkgs/ffigen/test/large_integration_tests/large_test.dart
+++ b/pkgs/ffigen/test/large_integration_tests/large_test.dart
@@ -2,13 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/header_parser.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 
 import '../test_utils.dart';
 
@@ -18,7 +16,7 @@
       logWarnings(Level.SEVERE);
     });
     test('Libclang test', () {
-      final config = Config.fromYaml(loadYaml('''
+      final config = testConfig('''
 ${strings.name}: LibClang
 ${strings.description}: Bindings to LibClang.
 ${strings.output}: unused
@@ -45,7 +43,7 @@
       dart-type: 'int'
 ${strings.preamble}: |
   // ignore_for_file: camel_case_types, non_constant_identifier_names
-      ''') as YamlMap);
+      ''');
       final library = parse(config);
 
       matchLibraryWithExpected(
@@ -60,7 +58,7 @@
     });
 
     test('CJSON test', () {
-      final config = Config.fromYaml(loadYaml('''
+      final config = testConfig('''
 ${strings.name}: CJson
 ${strings.description}: Bindings to Cjson.
 ${strings.output}: unused
@@ -73,7 +71,7 @@
     - '**cJSON.h'
 ${strings.preamble}: |
   // ignore_for_file: camel_case_types, non_constant_identifier_names
-      ''') as YamlMap);
+      ''');
       final library = parse(config);
 
       matchLibraryWithExpected(
@@ -86,7 +84,7 @@
     test('SQLite test', () {
       // Excluding functions that use 'va_list' because it can either be a
       // Pointer<__va_list_tag> or int depending on the OS.
-      final config = Config.fromYaml(loadYaml('''
+      final config = testConfig('''
 ${strings.name}: SQLite
 ${strings.description}: Bindings to SQLite.
 ${strings.output}: unused
@@ -105,7 +103,7 @@
     - sqlite3_str_vappendf
 ${strings.preamble}: |
   // ignore_for_file: camel_case_types, non_constant_identifier_names
-      ''') as YamlMap);
+      ''');
       final library = parse(config);
 
       matchLibraryWithExpected(
diff --git a/pkgs/ffigen/test/native_objc_test/util.dart b/pkgs/ffigen/test/native_objc_test/util.dart
index 1eb0746..7ef14bf 100644
--- a/pkgs/ffigen/test/native_objc_test/util.dart
+++ b/pkgs/ffigen/test/native_objc_test/util.dart
@@ -7,16 +7,17 @@
 import 'package:ffigen/ffigen.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
+
+import '../test_utils.dart';
 
 void generateBindingsForCoverage(String testName) {
   // The ObjC test bindings are generated in setup.dart (see #362), which means
   // that the ObjC related bits of ffigen are missed by test coverage. So this
   // function just regenerates those bindings. It doesn't test anything except
   // that the generation succeeded, by asserting the file exists.
-  final config = Config.fromYaml(loadYaml(
+  final config = testConfig(
       File(path.join('test', 'native_objc_test', '${testName}_config.yaml'))
-          .readAsStringSync()) as YamlMap);
+          .readAsStringSync());
   final library = parse(config);
   final file = File(
     path.join('test', 'debug_generated', '${testName}_test.dart'),
diff --git a/pkgs/ffigen/test/native_test/config.yaml b/pkgs/ffigen/test/native_test/config.yaml
index 6d8e475..901e559 100644
--- a/pkgs/ffigen/test/native_test/config.yaml
+++ b/pkgs/ffigen/test/native_test/config.yaml
@@ -8,10 +8,10 @@
 
 name: NativeLibrary
 description: 'Native tests.'
-output: 'test/native_test/native_test_bindings.dart'
+output: 'native_test_bindings.dart'
 headers:
   entry-points:
-    - 'test/native_test/native_test.c'
+    - 'native_test.c'
   include-directives:
     - '**native_test.c'
 
diff --git a/pkgs/ffigen/test/native_test/native_test.dart b/pkgs/ffigen/test/native_test/native_test.dart
index 4365214..7a19c2a 100644
--- a/pkgs/ffigen/test/native_test/native_test.dart
+++ b/pkgs/ffigen/test/native_test/native_test.dart
@@ -9,7 +9,6 @@
 import 'package:ffigen/ffigen.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart';
 import '../test_utils.dart';
 import 'native_test_bindings.dart';
 
@@ -30,26 +29,31 @@
     });
 
     test('generate_bindings', () {
-      final config = Config.fromYaml(loadYaml(
-          File(path.join('test', 'native_test', 'config.yaml'))
-              .readAsStringSync()) as YamlMap);
-      final library = parse(config);
-      final file = File(
+      final configFile =
+          File(path.join('test', 'native_test', 'config.yaml')).absolute;
+      final outFile = File(
         path.join('test', 'debug_generated', 'native_test_bindings.dart'),
-      );
-      library.generateFile(file);
+      ).absolute;
+
+      late Config config;
+      withChDir(configFile.path, () {
+        config = testConfigFromPath(configFile.path);
+      });
+      final library = parse(config);
+
+      library.generateFile(outFile);
 
       try {
-        final actual = file.readAsStringSync().replaceAll('\r', '');
+        final actual = outFile.readAsStringSync().replaceAll('\r', '');
         final expected = File(path.join(config.output))
             .readAsStringSync()
             .replaceAll('\r', '');
         expect(actual, expected);
-        if (file.existsSync()) {
-          file.delete();
+        if (outFile.existsSync()) {
+          outFile.delete();
         }
       } catch (e) {
-        print('Failed test: Debug generated file: ${file.absolute.path}');
+        print('Failed test: Debug generated file: ${outFile.absolute.path}');
         rethrow;
       }
     });
diff --git a/pkgs/ffigen/test/regen.dart b/pkgs/ffigen/test/regen.dart
index 5b0fc2c..1ee0df3 100644
--- a/pkgs/ffigen/test/regen.dart
+++ b/pkgs/ffigen/test/regen.dart
@@ -8,7 +8,7 @@
 import 'package:args/args.dart';
 import 'package:ffigen/ffigen.dart';
 import 'package:logging/logging.dart';
-import 'package:yaml/yaml.dart';
+import './test_utils.dart';
 
 const usage = r'''Regenerates the Dart FFI bindings used in tests and examples.
 
@@ -18,31 +18,12 @@
 $ dart run test/setup.dart && dart run test/regen.dart && dart test
 ''';
 
-Future<void> _regenConfig(File yamlConfig, File bindingOutput,
-    {bool chDir = false}) async {
+Future<void> _regenConfig(File yamlConfig, File bindingOutput) async {
   yamlConfig = yamlConfig.absolute;
   bindingOutput = bindingOutput.absolute;
-
-  Directory? oldDir;
-  var yaml = loadYaml(await yamlConfig.readAsString()) as YamlMap;
-
-  if (chDir) {
-    oldDir = Directory.current;
-    Directory.current = yamlConfig.parent;
-  }
-  try {
-    if (yaml.containsKey("ffigen")) {
-      yaml = yaml["ffigen"] as YamlMap;
-    }
-
-    final config = Config.fromYaml(yaml);
-    final library = parse(config);
-    library.generateFile(bindingOutput);
-  } finally {
-    if (oldDir != null) {
-      Directory.current = oldDir;
-    }
-  }
+  final config = testConfigFromPath(yamlConfig.path);
+  final library = parse(config);
+  library.generateFile(bindingOutput);
 }
 
 Future<void> main(List<String> args) async {
@@ -69,18 +50,25 @@
     print('${record.level.name}: ${record.time}: ${record.message}');
   });
 
-  await _regenConfig(File('test/native_test/config.yaml'),
-      File('test/native_test/native_test_bindings.dart'));
+  final nativeTestConfig = File('test/native_test/config.yaml').absolute;
+  final nativeTestOut =
+      File('test/native_test/native_test_bindings.dart').absolute;
+  await withChDir(nativeTestConfig.path,
+      () => _regenConfig(nativeTestConfig, nativeTestOut));
 
-  await _regenConfig(File('example/libclang-example/pubspec.yaml'),
-      File('example/libclang-example/generated_bindings.dart'),
-      chDir: true);
+  final libclangConfig = File('example/libclang-example/config.yaml').absolute;
+  final libclangOut =
+      File('example/libclang-example/generated_bindings.dart').absolute;
+  await withChDir(
+      libclangConfig.path, () => _regenConfig(libclangConfig, libclangOut));
 
-  await _regenConfig(File('example/simple/pubspec.yaml'),
-      File('example/simple/generated_bindings.dart'),
-      chDir: true);
+  final simpleConfig = File('example/simple/config.yaml').absolute;
+  final simpleOut = File('example/simple/generated_bindings.dart').absolute;
+  await withChDir(
+      simpleConfig.path, () => _regenConfig(simpleConfig, simpleOut));
 
-  await _regenConfig(File('example/c_json/pubspec.yaml'),
-      File('example/c_json/cjson_generated_bindings.dart'),
-      chDir: true);
+  final cJsonConfig = File('example/c_json/config.yaml').absolute;
+  final cJsonOut =
+      File('example/c_json/cjson_generated_bindings.dart').absolute;
+  await withChDir(cJsonConfig.path, () => _regenConfig(cJsonConfig, cJsonOut));
 }
diff --git a/pkgs/ffigen/test/rename_tests/rename_test.dart b/pkgs/ffigen/test/rename_tests/rename_test.dart
index 0b976a8..24a136a 100644
--- a/pkgs/ffigen/test/rename_tests/rename_test.dart
+++ b/pkgs/ffigen/test/rename_tests/rename_test.dart
@@ -3,11 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/config_provider.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:test/test.dart';
-import 'package:yaml/yaml.dart' as yaml;
 
 import '../test_utils.dart';
 
@@ -22,7 +20,7 @@
     setUpAll(() {
       logWarnings();
       expected = expectedLibrary();
-      actual = parser.parse(Config.fromYaml(yaml.loadYaml('''
+      actual = parser.parse(testConfig('''
 ${strings.name}: 'NativeLibrary'
 ${strings.description}: 'Rename Test'
 ${strings.output}: 'unused'
@@ -78,7 +76,7 @@
 ${strings.typedefs}:
   ${strings.rename}:
     'Struct5_Alias': 'Struct5_Alias_Renamed'
-    ''') as yaml.YamlMap));
+    '''));
     });
 
     test('Function addPrefix', () {
diff --git a/pkgs/ffigen/test/test_utils.dart b/pkgs/ffigen/test/test_utils.dart
index 93ea295..50cb30e 100644
--- a/pkgs/ffigen/test/test_utils.dart
+++ b/pkgs/ffigen/test/test_utils.dart
@@ -5,10 +5,13 @@
 import 'dart:io';
 
 import 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/config_provider/config.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
+import 'package:package_config/package_config_types.dart';
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
 
 extension LibraryTestExt on Library {
   /// Get a [Binding]'s generated string with a given name.
@@ -44,7 +47,7 @@
 // Remove '\r' for Windows compatibility, then apply user's normalizer.
 String _normalizeGeneratedCode(
     String generated, String Function(String)? codeNormalizer) {
-  final noCR = generated.replaceAll('\r', '');
+  final noCR = generated.replaceAll('\r', '').replaceAll(RegExp(r'\n+'), '\n');
   if (codeNormalizer == null) return noCR;
   return codeNormalizer(noCR);
 }
@@ -133,3 +136,37 @@
     logArr.add('${record.level.name.padRight(8)}: ${record.message}');
   });
 }
+
+Config testConfig(String yamlBody, {String? filename}) {
+  return Config.fromYaml(
+    yaml.loadYaml(yamlBody) as yaml.YamlMap,
+    filename: filename,
+    packageConfig: PackageConfig([
+      Package(
+        'shared_bindings',
+        Uri.file(path.join(path.current, 'example', 'shared_bindings', 'lib/')),
+      ),
+    ]),
+  );
+}
+
+Config testConfigFromPath(String path) {
+  final file = File(path);
+  final yamlBody = file.readAsStringSync();
+  return testConfig(yamlBody, filename: path);
+}
+
+T withChDir<T>(String path, T Function() inner) {
+  final oldDir = Directory.current;
+  Directory.current = File(path).parent;
+
+  late T result;
+
+  try {
+    result = inner();
+  } finally {
+    Directory.current = oldDir;
+  }
+
+  return result;
+}