/**
   *
   *
   * <pre>
   * Patron 2
   *     Food 1..2
   *     Drink 1..2
   * </pre>
   */
  @Test(timeout = 60000)
  public void breakChildrenSwap() {
    AstModel model = newModel();

    AstConcreteClafer patron = model.addChild("Patron").withCard(2, 2);
    AstConcreteClafer food = patron.addChild("Food").withCard(1, 2);
    AstConcreteClafer drink = patron.addChild("Drink").withCard(1, 2);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.defaultScope(3));
    assertEquals(5, solver.allInstances().length);
  }
  /**
   *
   *
   * <pre>
   * Person 2
   *     Likes -> Person
   * </pre>
   */
  @Test(timeout = 60000)
  public void dontBreakSingleCircularRef() {
    AstModel model = newModel();

    AstConcreteClafer person = model.addChild("Person").withCard(2, 2);
    AstConcreteClafer likes = person.addChild("Likes").refTo(person).withCard(Mandatory);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.defaultScope(2));
    assertEquals(3, solver.allInstances().length);
  }
  /**
   *
   *
   * <pre>
   * Patron 2
   *     Money ->> integer 1..2
   * </pre>
   */
  @Test(timeout = 60000)
  public void dontBreakUnrelatedRefs() {
    AstModel model = newModel();

    AstConcreteClafer patron = model.addChild("Patron").withCard(2, 2);
    AstConcreteClafer money = patron.addChild("Money").refTo(IntType).withCard(1, 2);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.defaultScope(4).intLow(0).intHigh(1));
    assertEquals(15, solver.allInstances().length);
  }
  /**
   *
   *
   * <pre>
   * A 3
   *     B ?
   * C -> A
   * D -> A
   * </pre>
   */
  @Test(timeout = 60000)
  public void breakTargetRefWithChildren() {
    AstModel model = newModel();

    AstConcreteClafer a = model.addChild("A").withCard(3, 3);
    AstConcreteClafer b = a.addChild("B").withCard(Optional);
    AstConcreteClafer c = model.addChild("C").refTo(a).withCard(Mandatory);
    AstConcreteClafer d = model.addChild("D").refTo(a).withCard(Mandatory);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.setScope(b, 1).defaultScope(3));
    assertEquals(7, solver.allInstances().length);
  }
  /**
   *
   *
   * <pre>
   * Patron 2
   *     Food +
   *         Cheese *
   * </pre>
   */
  @Test(timeout = 60000)
  public void breakGrandChildrenSwap() {
    /*
     * 19 nonisomorphic solutions:
     * Run "length $ nubBy isomorphic $ makeModel 3" with the Haskell code below.
     *
     *   import Control.Monad
     *   import Data.Functor
     *   import Data.List
     *
     *   data Model = Model {person1::Person, person2::Person} deriving (Eq, Ord, Show)
     *   data Person = Person {foods::[Food]} deriving (Eq, Ord, Show)
     *   data Food = Food {cheeses::[Cheese]} deriving (Eq, Ord, Show)
     *   data Cheese = Cheese deriving (Eq, Ord, Show)
     *
     *   people model = [person1 model, person2 model]
     *
     *   class Iso a where
     *       isomorphic :: a -> a -> Bool
     *
     *   instance Iso Model where
     *       isomorphic model1 model2 =
     *           ((person1 model1 `isomorphic` person1 model2) && (person2 model1 `isomorphic` person2 model2)) ||
     *           ((person1 model1 `isomorphic` person2 model2) && (person2 model1 `isomorphic` person1 model2))
     *
     *   instance Iso Person where
     *       isomorphic Person{foods = foods1} Person{foods = foods2}
     *           | length foods1 == length foods2 =
     *               or $ do
     *                   pfoods2 <- permutations foods2
     *                   return $ and $ zipWith isomorphic foods1 pfoods2
     *           | otherwise = False
     *
     *   instance Iso Food where
     *       isomorphic food1 food2 = length (cheeses food1) == length (cheeses food2)
     *
     *   instance Iso Cheese where
     *       isomorphic _ _ = True
     *
     *   numberOfFood = length . (>>= foods) . people
     *   numberOfCheese = length . (>>= cheeses) . (>>= foods) . people
     *
     *   printModel model =
     *       printPerson =<< people model
     *       where
     *           printPerson person = "Person\n" ++ (printFood =<< foods person)
     *           printFood food = "    Food\n" ++ (printCheese =<< cheeses food)
     *           printCheese _ = "        Cheese\n"
     *
     *   {-
     *    - Person 2
     *    -    Food +
     *    -        Cheese *
     *    -}
     *   makeModel scope =
     *       do
     *           p1 <- makePerson
     *           p2 <- makePerson
     *           let m = Model p1 p2
     *           guard $ numberOfFood m <= scope
     *           guard $ numberOfCheese m <= scope
     *           return m
     *       where
     *           makePerson = do
     *               feed <- [1..scope]
     *               Person <$> replicateM feed makeFood
     *           makeFood = do
     *               topping <- [0..scope]
     *               return $ Food $ replicate topping Cheese
     */
    AstModel model = newModel();

    AstConcreteClafer patron = model.addChild("Patron").withCard(2, 2);
    AstConcreteClafer food = patron.addChild("Food").withCard(1);
    AstConcreteClafer cheese = food.addChild("Cheese").withCard(0);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.defaultScope(3));
    assertEquals(19, solver.allInstances().length);
  }