CharmsModelImpl implements CharmsModel { @Override public boolean hasLearnedThresholdCharmsOfTrait(List<TraitType> requiredTraits, CategoryReference category, int threshold, int minimumEssence) { Charms charmsForTraits = findCharmsMatchingTraits(requiredTraits, category); int numberOfCharmsMatchingEssence = countCharmsThatMatchTheMinimumEssence(minimumEssence, charmsForTraits); return numberOfCharmsMatchingEssence >= threshold; } CharmsModelImpl(CharmsTemplate template); @Override Identifier getId(); @Override void initialize(HeroEnvironment environment, Hero hero); @Override void initializeListening(ChangeAnnouncer announcer); @Override void addCharmLearnListener(ICharmLearnListener listener); @Override Collection<CharmTree> getAllTrees(); @Override Collection<CharmTree> getTreesFor(CategoryReference reference); @Override Charm getCharmById(CharmName charmId); @Override boolean exists(CharmName charmId); @Override CharmSpecialLearningModel getCharmSpecialLearningModel(Charm charm); @Override void forgetAllAlienCharms(); @Override void addLearnableListener(ChangeListener listener); @Override final boolean isLearnable(Charm charm); @Override boolean hasLearnedThresholdCharmsWithKeyword(MagicAttribute attribute, int threshold); @Override boolean hasLearnedThresholdCharmsWithKeywordFromTree(
          TreeReference tree, MagicAttribute attribute, int threshold); @Override boolean hasLearnedThresholdCharmsOfTrait(List<TraitType> requiredTraits,
                                                  CategoryReference category, int threshold, int minimumEssence); @Override boolean hasLearnedThresholdCharmsOfAnyOneTrait(int threshold); @Override boolean isLearned(CharmName charmId); final boolean isForgettable(Charm charm); @Override final boolean isLearned(Charm charm); @Override LearningModel getLearningModel(); @Override boolean isAlienCharm(Charm charm); @Override CharmOptions getOptions();  }
@Test public void countsEachCharmOnlyOnce() throws Exception { DummyCharm charmWithTraitAndEssence = createCharmWithArcheryAndEssenceAtOne(); learnCharm(charmWithTraitAndEssence); boolean satisfied = model.hasLearnedThresholdCharmsOfTrait(newArrayList(Archery), null, 2, 1); assertThat(satisfied, is(false)); }
@Test public void countsCharmsWhenNoCategoryIsGiven() throws Exception { DummyCharm charmWithTraitAndEssence = createCharmWithArcheryAndEssenceAtOne(); learnCharm(charmWithTraitAndEssence); boolean satisfied = model.hasLearnedThresholdCharmsOfTrait(newArrayList(Archery), null, 1, 1); assertThat(satisfied, is(true)); }
@Test public void countsCharmsWhenCategoriesMatch() throws Exception { DummyCharm charmWithTraitAndEssence = createCharmWithArcheryAndEssenceAtOne(); learnCharm(charmWithTraitAndEssence); CategoryReference category = charmWithTraitAndEssence.getTreeReference().category; boolean satisfied = model.hasLearnedThresholdCharmsOfTrait(newArrayList(Archery), category, 1, 1); assertThat(satisfied, is(true)); }