static Map<String, JavaClassSignature> collectPublicAbiSignatures(Package pkg,
      String publicApiAnnotation) throws IOException {
    Map<String, JavaClassSignature> signatures = new LinkedHashMap<>();
    if (isPublicAbiPackage(pkg, publicApiAnnotation)) {
      PublicSignatureCollector collector = new PublicSignatureCollector();
      List<ClassFileTree.ClassFile> sortedClassFiles = pkg.getClassFiles().stream()
          .sorted(Comparator.comparing(ClassFile::getName)).toList();
      for (ClassFile klazz : sortedClassFiles) {
        try (InputStream is = klazz.getInputStream()) {
          new ClassReader(is).accept(collector, 0);
        }
      }
      signatures.putAll(collector.getClassSignatures());
    }
    List<ClassFileTree.Package> sortedSubPackages = pkg.getSubPackages().stream()
        .sorted(Comparator.comparing(Package::getFullyQualifiedName))
        .toList();
    for (ClassFileTree.Package subPkg : sortedSubPackages) {
      signatures.putAll(collectPublicAbiSignatures(subPkg, publicApiAnnotation));
    }
    return signatures;
  }
@Test
  public void testCollectPublicAbiSignatures() throws IOException {
    ClassFileTree.Package rootPkg = buildClassFileTree();

    Map<String, JavaClassSignature> signatures = AbiCheck
        .collectPublicAbiSignatures(rootPkg, Public.class.getCanonicalName());

    assertThat(signatures.size(), equalTo(1));
    JavaClassSignature rootSignature = signatures.get("root.Root");

    // PublicSignatureCollectorTest verifies actual signatures, no need to duplicate here
  }