// Path: src/main/java/ru/vyarus/guice/validator/group/ValidationContext.java
// @Singleton
// public class ValidationContext {
// 
//     private static final Class<?>[] EMPTY = new Class<?>[0];
//     private final ThreadLocal<List<Class<?>[]>> threadContext = new ThreadLocal<>();
// 
//     private final boolean addDefaultGroup;
// 
//     @Inject
//     public ValidationContext(@Named("guice.validator.addDefaultGroup") final boolean addDefaultGroup) {
//         this.addDefaultGroup = addDefaultGroup;
//     }
// 
//     /**
//      * @return current context validation groups or empty array when no groups defined
//      */
//     public Class<?>[] getContextGroups() {
//         Class<?>[] res = EMPTY;
//         final List<Class<?>[]> context = threadContext.get();
//         if (context != null) {
//             res = context.get(context.size() - 1);
//         }
//         return res;
//     }
// 
//     /**
//      * Defines context validation groups. Context is defined for all logic inside action callback
//      * (in current thread).
//      * Note: does not override current context groups.
//      *
//      * @param action action callback to be executed with validation groups
//      * @param groups validation groups to use
//      * @param <T>    action return type
//      * @return object produced by action callback
//      */
//     public <T> T doWithGroups(final GroupAction<T> action, final Class<?>... groups) {
//         pushContext(groups);
//         try {
//             return action.call();
//         } catch (Throwable ex) {
//             Throwables.throwIfUnchecked(ex);
//             throw new IllegalStateException(ex);
//         } finally {
//             popContext();
//         }
//     }
// 
//     @SuppressWarnings("PMD.UseVarargs")
//     private void pushContext(final Class<?>[] groups) {
//         List<Class<?>[]> context = threadContext.get();
//         if (context == null) {
//             context = new ArrayList<>();
//             threadContext.set(context);
//         }
//         // remove duplicates
//         final Set<Class<?>> allgroups = new LinkedHashSet<>();
//         if (!context.isEmpty()) {
//             Collections.addAll(allgroups, context.get(context.size() - 1));
//             // should not be applied otherwise because default group could be added manually
//             if (addDefaultGroup) {
//                 // default group will always be last (here it comes from upper context and must be removed)
//                 allgroups.remove(Default.class);
//             }
//         }
//         Collections.addAll(allgroups, groups);
//         context.add(allgroups.toArray(new Class<?>[0]));
//     }
// 
//     @SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
//     private void popContext() {
//         final List<Class<?>[]> context = threadContext.get();
//         if (context.size() > 1) {
//             context.remove(context.size() - 1);
//         } else {
//             threadContext.remove();
//         }
//     }
// }
// 
// Path: src/test/java/ru/vyarus/guice/validator/group/support/PropFunction.java
// public class PropFunction implements Function<ConstraintViolation, String> {
// 
//     @Override
//     public String apply(ConstraintViolation input) {
//         return Lists.newLinkedList(input.getPropertyPath()).getLast().toString();
//     }
// 
//     public static Set<String> convert(Collection<ConstraintViolation<?>> violations) {
//         return Sets.newHashSet(Iterables.transform(violations, new PropFunction()));
//     }
// }
// 
// Path: src/test/java/ru/vyarus/guice/validator/group/support/model/Model.java
// public class Model {
// 
//     @NotNull(groups = Group1.class)
//     private String foo;
// 
//     @NotNull(groups = Group2.class)
//     private String bar;
// 
//     @NotNull
//     private String def;
// 
//     public Model(String foo, String bar, String def) {
//         this.foo = foo;
//         this.bar = bar;
//         this.def = def;
//     }
// 
//     public String getFoo() {
//         return foo;
//     }
// 
//     public void setFoo(String foo) {
//         this.foo = foo;
//     }
// 
//     public String getBar() {
//         return bar;
//     }
// 
//     public void setBar(String bar) {
//         this.bar = bar;
//     }
// 
//     public String getDef() {
//         return def;
//     }
// 
//     public void setDef(String def) {
//         this.def = def;
//     }
// }


import com.google.common.collect.Sets;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runners.Parameterized;
import ru.vyarus.guice.validator.group.ValidationContext;
import ru.vyarus.guice.validator.group.support.PropFunction;
import ru.vyarus.guice.validator.group.support.groups.ann.Group1;
import ru.vyarus.guice.validator.group.support.groups.ann.Group2;
import ru.vyarus.guice.validator.group.support.model.Model;
import javax.inject.Inject;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Valid;
import jakarta.validation.executable.ValidateOnExecution;
import jakarta.validation.groups.Default;
import java.util.Collection;
import java.util.Set;
            Assert.assertEquals(3, props.size());
            Assert.assertEquals(Sets.newHashSet("foo", "bar", "def"), props);
        }
    }

    @Test
    public void testContextTree() throws Exception {
        service.contextTree(new Model("sample", "sample", "sample"));
        Assert.assertArrayEquals(new Class<?>[]{Group2.class, Group1.class, Default.class}, service.lastCallGroups);

        try {
            service.contextTree(new Model(null, "sample", "sample"));
            Assert.fail();
        } catch (ConstraintViolationException ex) {
            Set<String> props = PropFunction.convert(ex.getConstraintViolations());
            Assert.assertEquals(1, props.size());
            Assert.assertEquals(Sets.newHashSet("foo"), props);
        }
    }


    @Test
    public void testDuplicateGroups() throws Exception {
        service.duplicateGroups(new Model("sample", "sample", "sample"));
        Assert.assertArrayEquals(new Class<?>[]{Group1.class, Group2.class, Default.class}, service.lastCallGroups);
    }

    @ValidateOnExecution
    public static class Service {

// Path: src/main/java/ru/vyarus/guice/validator/group/ValidationContext.java
// @Singleton
// public class ValidationContext {
// 
//     private static final Class<?>[] EMPTY = new Class<?>[0];
//     private final ThreadLocal<List<Class<?>[]>> threadContext = new ThreadLocal<>();
// 
//     private final boolean addDefaultGroup;
// 
//     @Inject
//     public ValidationContext(@Named("guice.validator.addDefaultGroup") final boolean addDefaultGroup) {
//         this.addDefaultGroup = addDefaultGroup;
//     }
// 
//     /**
//      * @return current context validation groups or empty array when no groups defined
//      */
//     public Class<?>[] getContextGroups() {
//         Class<?>[] res = EMPTY;
//         final List<Class<?>[]> context = threadContext.get();
//         if (context != null) {
//             res = context.get(context.size() - 1);
//         }
//         return res;
//     }
// 
//     /**
//      * Defines context validation groups. Context is defined for all logic inside action callback
//      * (in current thread).
//      * Note: does not override current context groups.
//      *
//      * @param action action callback to be executed with validation groups
//      * @param groups validation groups to use
//      * @param <T>    action return type
//      * @return object produced by action callback
//      */
//     public <T> T doWithGroups(final GroupAction<T> action, final Class<?>... groups) {
//         pushContext(groups);
//         try {
//             return action.call();
//         } catch (Throwable ex) {
//             Throwables.throwIfUnchecked(ex);
//             throw new IllegalStateException(ex);
//         } finally {
//             popContext();
//         }
//     }
// 
//     @SuppressWarnings("PMD.UseVarargs")
//     private void pushContext(final Class<?>[] groups) {
//         List<Class<?>[]> context = threadContext.get();
//         if (context == null) {
//             context = new ArrayList<>();
//             threadContext.set(context);
//         }
//         // remove duplicates
//         final Set<Class<?>> allgroups = new LinkedHashSet<>();
//         if (!context.isEmpty()) {
//             Collections.addAll(allgroups, context.get(context.size() - 1));
//             // should not be applied otherwise because default group could be added manually
//             if (addDefaultGroup) {
//                 // default group will always be last (here it comes from upper context and must be removed)
//                 allgroups.remove(Default.class);
//             }
//         }
//         Collections.addAll(allgroups, groups);
//         context.add(allgroups.toArray(new Class<?>[0]));
//     }
// 
//     @SuppressWarnings("PMD.AvoidLiteralsInIfCondition")
//     private void popContext() {
//         final List<Class<?>[]> context = threadContext.get();
//         if (context.size() > 1) {
//             context.remove(context.size() - 1);
//         } else {
//             threadContext.remove();
//         }
//     }
// }
// 
// Path: src/test/java/ru/vyarus/guice/validator/group/support/PropFunction.java
// public class PropFunction implements Function<ConstraintViolation, String> {
// 
//     @Override
//     public String apply(ConstraintViolation input) {
//         return Lists.newLinkedList(input.getPropertyPath()).getLast().toString();
//     }
// 
//     public static Set<String> convert(Collection<ConstraintViolation<?>> violations) {
//         return Sets.newHashSet(Iterables.transform(violations, new PropFunction()));
//     }
// }
// 
// Path: src/test/java/ru/vyarus/guice/validator/group/support/model/Model.java
// public class Model {
// 
//     @NotNull(groups = Group1.class)
//     private String foo;
// 
//     @NotNull(groups = Group2.class)
//     private String bar;
// 
//     @NotNull
//     private String def;
// 
//     public Model(String foo, String bar, String def) {
//         this.foo = foo;
//         this.bar = bar;
//         this.def = def;
//     }
// 
//     public String getFoo() {
//         return foo;
//     }
// 
//     public void setFoo(String foo) {
//         this.foo = foo;
//     }
// 
//     public String getBar() {
//         return bar;
//     }
// 
//     public void setBar(String bar) {
//         this.bar = bar;
//     }
// 
//     public String getDef() {
//         return def;
//     }
// 
//     public void setDef(String def) {
//         this.def = def;
//     }
// }


// Path: src/test/java/ru/vyarus/guice/validator/GroupsTest.java
import com.google.common.collect.Sets;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runners.Parameterized;
import ru.vyarus.guice.validator.group.ValidationContext;
import ru.vyarus.guice.validator.group.support.PropFunction;
import ru.vyarus.guice.validator.group.support.groups.ann.Group1;
import ru.vyarus.guice.validator.group.support.groups.ann.Group2;
import ru.vyarus.guice.validator.group.support.model.Model;
import javax.inject.Inject;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Valid;
import jakarta.validation.executable.ValidateOnExecution;
import jakarta.validation.groups.Default;
import java.util.Collection;
import java.util.Set;

            Assert.assertEquals(3, props.size());
            Assert.assertEquals(Sets.newHashSet("foo", "bar", "def"), props);
        }
    }

    @Test
    public void testContextTree() throws Exception {
        service.contextTree(new Model("sample", "sample", "sample"));
        Assert.assertArrayEquals(new Class<?>[]{Group2.class, Group1.class, Default.class}, service.lastCallGroups);

        try {
            service.contextTree(new Model(null, "sample", "sample"));
            Assert.fail();
        } catch (ConstraintViolationException ex) {
            Set<String> props = PropFunction.convert(ex.getConstraintViolations());
            Assert.assertEquals(1, props.size());
            Assert.assertEquals(Sets.newHashSet("foo"), props);
        }
    }


    @Test
    public void testDuplicateGroups() throws Exception {
        service.duplicateGroups(new Model("sample", "sample", "sample"));
        Assert.assertArrayEquals(new Class<?>[]{Group1.class, Group2.class, Default.class}, service.lastCallGroups);
    }

    @ValidateOnExecution
    public static class Service {

        @Inject