public static Result validate(Profile profile, SchemaSpecification specification, PlanetilerConfig config) {
    var featureCollectorFactory = new FeatureCollector.Factory(config, Stats.inMemory());
    return new Result(specification.examples().stream().map(example -> new ExampleResult(example, Try.apply(() -> {
      List<String> issues = new ArrayList<>();
      var input = example.input();
      var expectedFeatures = example.output();
      var geometry = parseGeometry(input.geometry());
      var feature = SimpleFeature.create(geometry, input.tags(), input.source(), null, 0);
      var collector = featureCollectorFactory.get(feature);
      profile.processFeature(feature, collector);
      List<FeatureWithOverrides> result = new ArrayList<>();
      Set<Integer> zooms = expectedFeatures.stream().map(f -> f.atZoom()).collect(Collectors.toSet());
      for (var outputFeature : collector) {
        if (outputFeature.hasLinearRanges()) {
          for (var zoom : zooms) {
            for (var range : outputFeature.getLinearRangesAtZoom(zoom)) {
              result.add(new FeatureWithOverrides(outputFeature, range));
            }
          }
        } else {
          result.add(new FeatureWithOverrides(outputFeature, null));
        }
      }
      if (result.size() != expectedFeatures.size()) {
        issues.add(
          "Different number of elements, expected=%s actual=%s".formatted(expectedFeatures.size(), result.size()));
      } else {
        // TODO print a diff of the input and output feature YAML representations
        for (int i = 0; i < expectedFeatures.size(); i++) {
          var expected = expectedFeatures.get(i);
          var actual = result.stream().max(proximityTo(expected)).orElseThrow();
          result.remove(actual);
          var actualTags =
            actual.overrides != null ? actual.overrides.attrs() : actual.feature.getAttrsAtZoom(expected.atZoom());
          String prefix = "feature[%d]".formatted(i);
          validate(prefix + ".layer", issues, expected.layer(), actual.feature.getLayer());
          validate(prefix + ".minzoom", issues, expected.minZoom(), actual.feature.getMinZoom());
          validate(prefix + ".maxzoom", issues, expected.maxZoom(), actual.feature.getMaxZoom());
          validate(prefix + ".minsize", issues, expected.minSize(),
            actual.feature.getMinPixelSizeAtZoom(expected.atZoom()));
          validate(prefix + ".geometry", issues, expected.geometry(),
            GeometryType.typeOf(actual.feature.getGeometry()));
          Set<String> tags = new TreeSet<>(actualTags.keySet());
          expected.tags().forEach((tag, value) -> {
            validate(prefix + ".tags[\"%s\"]".formatted(tag), issues, value, actualTags.get(tag), false);
            tags.remove(tag);
          });
          if (Boolean.FALSE.equals(expected.allowExtraTags())) {
            for (var tag : tags) {
              validate(prefix + ".tags[\"%s\"]".formatted(tag), issues, null, actualTags.get(tag), false);
            }
          }
        }
      }
      return issues;
    }))).toList());
  }
Returns the result of validating {@code profile} against the examples in {@code specification}.
planetiler-core/src/main/java/com/onthegomap/planetiler/validator/BaseSchemaValidator.java