// Path: promagent-framework/promagent-api/src/main/java/io/promagent/hookcontext/MetricsStore.java
// public class MetricsStore {
// 
//     private final CollectorRegistry registry;
//     private final ConcurrentMap<String, Collector> metrics = new ConcurrentHashMap<>();
// 
//     public MetricsStore(CollectorRegistry registry) {
//         this.registry = registry;
//     }
// 
//     /**
//      * See {@link MetricsStore} and {@link MetricDef#MetricDef(String, BiFunction)}.
//      */
//     @SuppressWarnings("unchecked")
//     public <T extends Collector> T createOrGet(MetricDef<T> metricDef) {
//         return (T) metrics.computeIfAbsent(metricDef.getMetricName(), s -> metricDef.getProducer().apply(metricDef.getMetricName(), registry));
//     }
// }
// 
// Path: promagent-framework/promagent-internal/src/test/java/io/promagent/internal/instrumentationtests/MethodCallCounter.java
// public class MethodCallCounter {
// 
//     public static void reset() {
//         captures.clear();
//     }
// 
//     public static void observe(Object hook, String methodName, Object... args) {
//         captures.add(new Capture(hook, methodName, args));
//     }
// 
//     public static void assertNumCalls(int expectedNumberOfCalls, Class<?> hookClass, String hookMethod, Object... expectedArgs) {
//         List<Capture> matching = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .filter(c -> c.hookMethod.equals(hookMethod))
//                 .filter(c -> Arrays.equals(expectedArgs, c.args))
//                 .collect(Collectors.toList());
//         Assertions.assertEquals(expectedNumberOfCalls, matching.size());
//     }
// 
//     // special case for the varargsMixed test
//     public static void assertNumCalls(int expectedNumberOfCalls, Class<?> hookClass, String hookMethod, String firstString, String... moreStrings) {
//         List<Capture> matching = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .filter(c -> c.hookMethod.equals(hookMethod))
//                 .filter(c -> c.args.length == 2)
//                 .filter(c -> Objects.equals(firstString, c.args[0]))
//                 .filter(c -> Arrays.equals(moreStrings, (String[]) c.args[1]))
//                 .collect(Collectors.toList());
//         Assertions.assertEquals(expectedNumberOfCalls, matching.size());
//     }
// 
//     public static void assertNumHookInstances(int expectedNumberOfInstances, Class<?> hookClass) {
//         long actualNumberOfInstances = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .map(c -> c.hook)
//                 .distinct()
//                 .count();
//         Assertions.assertEquals(expectedNumberOfInstances, (int) actualNumberOfInstances);
//     }
// 
//     private static class Capture {
//         final Object hook;
//         final String hookMethod;
//         final Object[] args;
// 
//         Capture(Object hook, String hookMethod, Object[] args) {
//             this.hook = hook;
//             this.hookMethod = hookMethod;
//             this.args = args;
//         }
//     }
// 
//     private static final List<Capture> captures = Collections.synchronizedList(new ArrayList<>());
// 
//     private MethodCallCounter() {}
// }
// 
// Path: promagent-framework/promagent-internal/src/test/java/io/promagent/internal/instrumentationtests/classes/Fruit.java
// public class Fruit {
//     public static class Orange extends Fruit{}
// }


import io.promagent.annotations.Before;
import io.promagent.annotations.Hook;
import io.promagent.hookcontext.MetricsStore;
import io.promagent.internal.instrumentationtests.MethodCallCounter;
import io.promagent.internal.instrumentationtests.classes.Fruit;
package io.promagent.internal.instrumentationtests.hooks;


/**
 * Two hooks instrumenting the same class.
 */
public class TwoHooks {

    @Hook(instruments = "io.promagent.internal.instrumentationtests.classes.ParameterTypesExample")
    public static class HookOne {

        public HookOne(MetricsStore m) {}

        @Before(method = "objects")
        public void before(Object o, Fruit f, Fruit.Orange x) {
            MethodCallCounter.observe(this, "before", o, f, x);
        }
    }

    @Hook(instruments = "io.promagent.internal.instrumentationtests.classes.ParameterTypesExample")
    public static class HookTwo {

// Path: promagent-framework/promagent-api/src/main/java/io/promagent/hookcontext/MetricsStore.java
// public class MetricsStore {
// 
//     private final CollectorRegistry registry;
//     private final ConcurrentMap<String, Collector> metrics = new ConcurrentHashMap<>();
// 
//     public MetricsStore(CollectorRegistry registry) {
//         this.registry = registry;
//     }
// 
//     /**
//      * See {@link MetricsStore} and {@link MetricDef#MetricDef(String, BiFunction)}.
//      */
//     @SuppressWarnings("unchecked")
//     public <T extends Collector> T createOrGet(MetricDef<T> metricDef) {
//         return (T) metrics.computeIfAbsent(metricDef.getMetricName(), s -> metricDef.getProducer().apply(metricDef.getMetricName(), registry));
//     }
// }
// 
// Path: promagent-framework/promagent-internal/src/test/java/io/promagent/internal/instrumentationtests/MethodCallCounter.java
// public class MethodCallCounter {
// 
//     public static void reset() {
//         captures.clear();
//     }
// 
//     public static void observe(Object hook, String methodName, Object... args) {
//         captures.add(new Capture(hook, methodName, args));
//     }
// 
//     public static void assertNumCalls(int expectedNumberOfCalls, Class<?> hookClass, String hookMethod, Object... expectedArgs) {
//         List<Capture> matching = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .filter(c -> c.hookMethod.equals(hookMethod))
//                 .filter(c -> Arrays.equals(expectedArgs, c.args))
//                 .collect(Collectors.toList());
//         Assertions.assertEquals(expectedNumberOfCalls, matching.size());
//     }
// 
//     // special case for the varargsMixed test
//     public static void assertNumCalls(int expectedNumberOfCalls, Class<?> hookClass, String hookMethod, String firstString, String... moreStrings) {
//         List<Capture> matching = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .filter(c -> c.hookMethod.equals(hookMethod))
//                 .filter(c -> c.args.length == 2)
//                 .filter(c -> Objects.equals(firstString, c.args[0]))
//                 .filter(c -> Arrays.equals(moreStrings, (String[]) c.args[1]))
//                 .collect(Collectors.toList());
//         Assertions.assertEquals(expectedNumberOfCalls, matching.size());
//     }
// 
//     public static void assertNumHookInstances(int expectedNumberOfInstances, Class<?> hookClass) {
//         long actualNumberOfInstances = captures.stream()
//                 .filter(c -> c.hook.getClass().equals(hookClass))
//                 .map(c -> c.hook)
//                 .distinct()
//                 .count();
//         Assertions.assertEquals(expectedNumberOfInstances, (int) actualNumberOfInstances);
//     }
// 
//     private static class Capture {
//         final Object hook;
//         final String hookMethod;
//         final Object[] args;
// 
//         Capture(Object hook, String hookMethod, Object[] args) {
//             this.hook = hook;
//             this.hookMethod = hookMethod;
//             this.args = args;
//         }
//     }
// 
//     private static final List<Capture> captures = Collections.synchronizedList(new ArrayList<>());
// 
//     private MethodCallCounter() {}
// }
// 
// Path: promagent-framework/promagent-internal/src/test/java/io/promagent/internal/instrumentationtests/classes/Fruit.java
// public class Fruit {
//     public static class Orange extends Fruit{}
// }


// Path: promagent-framework/promagent-internal/src/test/java/io/promagent/internal/instrumentationtests/hooks/TwoHooks.java
import io.promagent.annotations.Before;
import io.promagent.annotations.Hook;
import io.promagent.hookcontext.MetricsStore;
import io.promagent.internal.instrumentationtests.MethodCallCounter;
import io.promagent.internal.instrumentationtests.classes.Fruit;

package io.promagent.internal.instrumentationtests.hooks;


/**
 * Two hooks instrumenting the same class.
 */
public class TwoHooks {

    @Hook(instruments = "io.promagent.internal.instrumentationtests.classes.ParameterTypesExample")
    public static class HookOne {

        public HookOne(MetricsStore m) {}

        @Before(method = "objects")
        public void before(Object o, Fruit f, Fruit.Orange x) {
            MethodCallCounter.observe(this, "before", o, f, x);
        }
    }

    @Hook(instruments = "io.promagent.internal.instrumentationtests.classes.ParameterTypesExample")
    public static class HookTwo {

        public HookTwo(MetricsStore m) {}