code: package cgm;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertTrue;
  
  import java.util.HashSet;
  
  import org.junit.Test;
  
  public class RefinementTest {
  
  	@Test
  	public void shouldReturnMyType() {
  		Refinement goal = new Goal(false);
  		Task task = new Task();
  		Delegation delegation = new Delegation();
  
  		assertEquals(Refinement.GOAL, goal.myType());
  
  		assertEquals(Refinement.TASK, task.myType());
  
  		assertEquals(Refinement.DELEGATION, delegation.myType());
  	}
  
  	@Test
  	public void shouldBeApplicable() throws Exception {
  		Refinement goal = new Goal(false);
  		Task task = new Task();
  		Delegation delegation = new Delegation();
  
  		Context current = new Context("c1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		task.addApplicableContext(current);
  		goal.addApplicableContext(current);
  		delegation.addApplicableContext(current);
  
  		assertTrue(goal.isApplicable(fullContext));
  		assertTrue(task.isApplicable(fullContext));
  		assertTrue(delegation.isApplicable(fullContext));
  	}
  
  	@Test
  	public void shouldBeNotApplicable() throws Exception {
  		Refinement goal = new Goal(false);
  		Task task = new Task();
  		Delegation delegation = new Delegation();
  
  		Context context = new Context("C1");
  
  		task.addApplicableContext(context);
  		goal.addApplicableContext(context);
  		delegation.addApplicableContext(context);
  
  		Context wrongContext = new Context("C2");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(wrongContext);
  
  		assertFalse(goal.isApplicable(fullContext));
  		assertFalse(task.isApplicable(fullContext));
  		assertFalse(delegation.isApplicable(fullContext));
  	}
  
  	@Test
  	public void aTaskShouldBeAchievable() throws Exception {
  		Task task = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task.addApplicableContext(current);
  		task.setProvidedQuality(current, Metric.SECONDS, 12);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		assertTrue(task.isAchievable(fullContext, interp).getTasks().contains(task));
  	}
  
  	@Test
  	public void aTaskMayNotBeAchievable() throws Exception {
  		Task task = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task.addApplicableContext(current);
  		task.setProvidedQuality(current, Metric.SECONDS, 16);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		assertEquals(null, task.isAchievable(fullContext, interp));
  	}
  
  	@Test
  	public void aNonApplicableRootGoalIsNotAchievable() throws Exception {
  		Goal goal = new Goal(false);
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  		goal.addApplicableContext((new Context("C2")));
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		assertEquals(null, goal.isAchievable(fullContext, interp));
  	}
  
  	@Test
  	public void aGoalWithATaskMayBeAchievable() throws Exception {
  		Goal goal = new Goal(false);
  
  		Task task = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		task.addApplicableContext(current);
  		task.setProvidedQuality(current, Metric.SECONDS, 13);
  
  		goal.addDependency(task);
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertEquals(1, plan.getTasks().size());
  	}
  
  	@Test
  	public void aGoalAndDecomposedWithTwoTasksMayBeAchievable() throws Exception {
  		Goal goal = new Goal(false);
  		assertTrue(goal.isAndDecomposition());
  
  		Task task1 = new Task();
  		Task task2 = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task1.addApplicableContext(current);
  		task1.setProvidedQuality(current, Metric.SECONDS, 13);
  
  		task2.addApplicableContext(current);
  		task2.setProvidedQuality(current, Metric.SECONDS, 11);
  
  		goal.addDependency(task1);
  		goal.addDependency(task2);
  
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertEquals(2, plan.getTasks().size());
  	}
  
  	@Test
  	public void aGoalAndDecomposedWithTwoTasksMayNotBeAchievable() throws Exception {
  		Goal goal = new Goal(false);
  		assertTrue(goal.isAndDecomposition());
  
  		Task task1 = new Task();
  		Task task2 = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task1.addApplicableContext(current);
  		task1.setProvidedQuality(current, Metric.SECONDS, 16);
  
  		task2.addApplicableContext(current);
  		task2.setProvidedQuality(current, Metric.SECONDS, 11);
  
  		goal.addDependency(task1);
  		goal.addDependency(task2);
  
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertEquals(null, plan);
  	}
  
  	@Test
  	public void aGoalOrDecomposedWithTwoTasksMayBeAchievable() throws Exception {
  		Goal goal = new Goal(true);
  		assertTrue(goal.isOrDecomposition());
  
  		Task task1 = new Task();
  		Task task2 = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task1.addApplicableContext(current);
  		task1.setProvidedQuality(current, Metric.SECONDS, 13);
  
  		task2.addApplicableContext(current);
  		task2.setProvidedQuality(current, Metric.SECONDS, 11);
  
  		goal.addDependency(task1);
  		goal.addDependency(task2);
  
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertEquals(1, plan.getTasks().size());
  	}
  
  	@Test
  	public void aGoalOrDecomposedWithTwoTasksMayBeAchievableAtOnlyOneBranch() throws Exception {
  		Goal goal = new Goal(true);
  		assertTrue(goal.isOrDecomposition());
  
  		Task task1 = new Task();
  		Task task2 = new Task();
  
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task1.addApplicableContext(current);
  		task1.setProvidedQuality(current, Metric.SECONDS, 16);
  
  		task2.addApplicableContext(current);
  		task2.setProvidedQuality(current, Metric.SECONDS, 11);
  
  		goal.addDependency(task1);
  		goal.addDependency(task2);
  
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertTrue(plan.getTasks().contains(task2));
  		assertTrue(!plan.getTasks().contains(task1));
  	}
  
  	@Test
  	public void aGoalOrDecomposedWithTwoTasksMayNotBeAchievable() throws Exception {
  		Goal goal = new Goal(true);
  
  		Task task1 = new Task();
  		Task task2 = new Task();
  		Context current = new Context("C1");
  		HashSet<Context> fullContext = new HashSet<Context>();
  		fullContext.add(current);
  
  		QualityConstraint qc = new QualityConstraint(current, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task1.addApplicableContext(current);
  		task1.setProvidedQuality(current, Metric.SECONDS, 16);
  
  		task2.addApplicableContext(current);
  		task2.setProvidedQuality(current, Metric.SECONDS, 17);
  
  		goal.addDependency(task1);
  		goal.addDependency(task2);
  
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(current);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		Plan plan = goal.isAchievable(fullContext, interp);
  		assertTrue(goal.isOrDecomposition());
  		assertEquals(null, plan);
  	}
  
  	@Test
  	public void testApplicableDeps() {
  		Pragmatic goal = new Pragmatic(false);
  
  		Task task = new Task();
  		Context context = new Context("C1");
  		Context wrongContext = new Context("C2");
  		HashSet<Context> current = new HashSet<Context>();
  
  		QualityConstraint qc = new QualityConstraint(context, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task.addApplicableContext(context);
  		task.setProvidedQuality(context, Metric.SECONDS, 13);
  
  		goal.addDependency(task);
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(context);
  		goal.getInterpretation().addQualityConstraint(qc);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		current.add(wrongContext);
  		assertEquals(null, goal.isAchievable(current, interp));
  
  		current.add(context);
  		assertEquals(1, goal.isAchievable(current, interp).getTasks().size());
  
  	}
  
  	@Test
  	public void testGetApplicableQC() {
  		Pragmatic goal = new Pragmatic(false);
  
  		Task task = new Task();
  		Context context = new Context("C1");
  		Context anotherContext = new Context("C2");
  
  		HashSet<Context> fullContext = new HashSet<Context>();
  
  		QualityConstraint qc = new QualityConstraint(context, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  		QualityConstraint stricter = new QualityConstraint(anotherContext, Metric.SECONDS, 10,
  				Comparison.LESS_OR_EQUAL_TO);
  
  		goal.addDependency(task);
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(context);
  		goal.getInterpretation().addQualityConstraint(qc);
  		goal.getInterpretation().addQualityConstraint(stricter);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		fullContext.add(context);
  		// assertEquals(null, goal.isAchievable(fullContext, interp));
  
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(qc));
  
  		fullContext.add(anotherContext);
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(qc));
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(stricter));
  
  		fullContext.remove(context);
  		assertTrue(!goal.getInterpretation().getQualityConstraints(fullContext).contains(qc));
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(stricter));
  
  	}
  
  	@Test
  	public void shouldThereBeMoreThanOneApplicableQCreturnTheStricterOne() throws DifferentMetricsException {
  		Pragmatic goal = new Pragmatic(false);
  
  		Task task = new Task();
  		Context context = new Context("C1");
  		Context anotherContext = new Context("C2");
  
  		HashSet<Context> fullContext = new HashSet<Context>();
  
  		QualityConstraint qc = new QualityConstraint(context, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  		QualityConstraint stricter = new QualityConstraint(anotherContext, Metric.SECONDS, 10,
  				Comparison.LESS_OR_EQUAL_TO);
  
  		goal.addDependency(task);
  		goal.setIdentifier("Root");
  		goal.addApplicableContext(context);
  		goal.getInterpretation().addQualityConstraint(qc);
  		goal.getInterpretation().addQualityConstraint(stricter);
  
  		assertEquals(stricter, qc.stricterQC(stricter));
  
  		fullContext.add(context);
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(qc));
  
  		fullContext.add(anotherContext);
  		assertTrue(goal.getInterpretation().getQualityConstraints(fullContext).contains(stricter));
  
  	}
  
  	@Test
  	public void shouldIncludeNonApplicableContexts() {
  		Pragmatic goal = new Pragmatic(false);
  
  		Task task = new Task();
  		Context context = new Context("C1");
  		Context wrongContext = new Context("C2");
  		HashSet<Context> current = new HashSet<Context>();
  
  		QualityConstraint qc = new QualityConstraint(context, Metric.SECONDS, 15, Comparison.LESS_OR_EQUAL_TO);
  
  		task.addApplicableContext(context);
  		task.setProvidedQuality(context, Metric.SECONDS, 13);
  
  		goal.addDependency(task);
  		goal.setIdentifier("Root");
  		goal.addNonApplicableContext(wrongContext);
  		goal.getInterpretation().addQualityConstraint(qc);
  
  		Interpretation interp = new Interpretation();
  		interp.addQualityConstraint(qc);
  
  		current.add(wrongContext);
  		assertEquals(null, goal.isAchievable(current, interp));
  
  		current.add(context);
  		assertEquals(null, goal.isAchievable(current, interp));
  
  		current.remove(wrongContext);
  		assertTrue(goal.isAchievable(current, interp) != null);
  		assertTrue(goal.isAchievable(current, interp).getTasks() != null);
  		assertEquals(1, goal.isAchievable(current, interp).getTasks().size());
  
  	}
  
  	@Test
  	public void shouldAddSeveralContextsAtOnce(){
  		Context context1 = new Context("C1");
  		Context context2 = new Context("C2");
  		
  		Task task = new Task();
  		int originalSize = task.getApplicableContext().size();
  		HashSet<Context> set = new HashSet<Context>();
  		
  		set.add(context1);
  		set.add(context2);
  		
  		task.addApplicableContext(set);
  		// null is always an applicable context
  		assertEquals(2, task.getApplicableContext().size() - originalSize);
  	}
  }
  