<commit_before>package com.temenos.interaction.core.hypermedia;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;

import org.junit.Before;
import org.junit.Test;

import com.temenos.interaction.core.MultivaluedMapImpl;
import com.temenos.interaction.core.hypermedia.ASTValidation;
import com.temenos.interaction.core.hypermedia.ResourceState;
import com.temenos.interaction.core.hypermedia.ResourceStateMachine;
import com.temenos.interaction.core.resource.CollectionResource;
import com.temenos.interaction.core.resource.EntityResource;
import com.temenos.interaction.core.web.RequestContext;

public class TestResourceStateMachine {

	@Before
	public void setup() {
		// initialise the thread local request context with requestUri and baseUri
		UriBuilder baseUri = UriBuilder.fromUri("/baseuri");
		String requestUri = "/baseuri/";
        RequestContext ctx = new RequestContext(baseUri, requestUri, null);
        RequestContext.setRequestContext(ctx);
	}

	/*
	 * Evaluate custom link relation, via the Link header.  See (see rfc5988)
	 * We return a Link if the header is set and the @{link Transition} can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForCustomLinkRelation() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster");
		ResourceState cookingState = new ResourceState("toaster", "cooking", "/machines/toaster/cooking");

		// view the resource if the toaster is cooking (could be time remaining)
		existsState.addTransition("GET", cookingState);
		// stop the toast cooking
		cookingState.addTransition("DELETE", existsState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		// mock the Link header
		LinkHeader linkHeader = LinkHeader.valueOf("</path>; rel=\"toaster.cooking>toaster.exists\"");

		Link targetLink = stateMachine.getLinkFromRelations(mock(MultivaluedMap.class), testResponseEntity, cookingState, linkHeader);

		assertNotNull(targetLink);
		assertEquals("/baseuri/machines/toaster", targetLink.getHref());
		assertEquals("toaster.cooking>toaster.exists", targetLink.getTitle());
	}


	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForTargetState() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster");
		ResourceState cookingState = new ResourceState("toaster", "cooking", "/machines/toaster/cooking");

		// view the resource if the toaster is cooking (could be time remaining)
		existsState.addTransition("GET", cookingState);
		// stop the toast cooking
		cookingState.addTransition("DELETE", existsState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, cookingState, "DELETE");

		assertNotNull(targetLink);
		assertEquals("/baseuri/machines/toaster", targetLink.getHref());
		assertEquals("toaster.cooking>toaster.exists", targetLink.getTitle());
	}

	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForSelfState() {
		CollectionResourceState collectionState = new CollectionResourceState("machines", "MachineView", "/machines");

		// create machines
		collectionState.addTransition("POST", collectionState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(collectionState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, collectionState, "POST");

		assertNotNull(targetLink);
		// a target link the same as our current state equates to 205 Reset Content
		assertEquals("/baseuri/machines", targetLink.getHref());
		// we use createSelfLink under the covers so link id looks like transition to self
		assertEquals("machines.MachineView>machines.MachineView", targetLink.getTitle());
	}

	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 * When the target state is a pseudo final state, no link will be returned.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForFinalPseudoState() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster/{id}");
		ResourceState deletedState = new ResourceState("toaster", "cooking", null);

		// delete the toaster
		existsState.addTransition("DELETE", deletedState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, existsState, "DELETE");

		// no target link equates to 204 No Content
		assertNull(targetLink);
	}

	@Test
	public void testStates() {
		String ENTITY_NAME = "T24CONTRACT";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
		ResourceState unauthorised = new ResourceState(ENTITY_NAME, "INAU", "unauthorised/{id}");
		ResourceState authorised = new ResourceState(ENTITY_NAME, "LIVE", "authorised/{id}");
		ResourceState reversed = new ResourceState(ENTITY_NAME, "RNAU", "reversed/{id}");
		ResourceState history = new ResourceState(ENTITY_NAME, "REVE", "history/{id}");
		ResourceState end = new ResourceState(ENTITY_NAME, "end", "{id}");
	
		begin.addTransition("PUT", unauthorised);
		
		unauthorised.addTransition("PUT", unauthorised);
		unauthorised.addTransition("PUT", authorised);
		unauthorised.addTransition("DELETE", end);
		
		authorised.addTransition("PUT", history);
		
		history.addTransition("PUT", reversed);
		
		
		ResourceStateMachine sm = new ResourceStateMachine(begin);
		assertEquals(6, sm.getStates().size());
		
		Set<ResourceState> testStates = new HashSet<ResourceState>();
		testStates.add(begin);
		testStates.add(unauthorised);
		testStates.add(authorised);
		testStates.add(reversed);
		testStates.add(history);
		testStates.add(end);
		for (ResourceState s : testStates) {
			assertTrue(sm.getStates().contains(s));
		}
		
		System.out.println(new ASTValidation().graph(sm));
	}
	
	@Test
	public void testGetStates() {
		String ENTITY_NAME = "";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
		ResourceState exists = new ResourceState(ENTITY_NAME, "exists", "{id}");
		ResourceState end = new ResourceState(ENTITY_NAME, "end", "{id}");
	
		begin.addTransition("PUT", exists);
		exists.addTransition("PUT", exists);
		exists.addTransition("DELETE", end);
		
		ResourceStateMachine sm = new ResourceStateMachine(begin);
		Collection<ResourceState> states = sm.getStates();
		assertEquals("Number of states", 3, states.size());
		assertTrue(states.contains(begin));
		assertTrue(states.contains(exists));
		assertTrue(states.contains(end));
	}

	@Test
	public void testInteractionMap() {
		String ENTITY_NAME = "";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");<commit_msg>Slightly improved test documentation and add a new test for transitions.<commit_after>package com.temenos.interaction.core.hypermedia;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;

import org.junit.Before;
import org.junit.Test;

import com.temenos.interaction.core.MultivaluedMapImpl;
import com.temenos.interaction.core.hypermedia.ASTValidation;
import com.temenos.interaction.core.hypermedia.ResourceState;
import com.temenos.interaction.core.hypermedia.ResourceStateMachine;
import com.temenos.interaction.core.resource.CollectionResource;
import com.temenos.interaction.core.resource.EntityResource;
import com.temenos.interaction.core.web.RequestContext;

public class TestResourceStateMachine {

	@Before
	public void setup() {
		// initialise the thread local request context with requestUri and baseUri
		UriBuilder baseUri = UriBuilder.fromUri("/baseuri");
		String requestUri = "/baseuri/";
        RequestContext ctx = new RequestContext(baseUri, requestUri, null);
        RequestContext.setRequestContext(ctx);
	}

	/*
	 * Evaluate custom link relation, via the Link header.  See (see rfc5988)
	 * We return a Link if the header is set and the @{link Transition} can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForCustomLinkRelation() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster");
		ResourceState cookingState = new ResourceState("toaster", "cooking", "/machines/toaster/cooking");

		// view the resource if the toaster is cooking (could be time remaining)
		existsState.addTransition("GET", cookingState);
		// stop the toast cooking
		cookingState.addTransition("DELETE", existsState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		// mock the Link header
		LinkHeader linkHeader = LinkHeader.valueOf("</path>; rel=\"toaster.cooking>toaster.exists\"");

		Link targetLink = stateMachine.getLinkFromRelations(mock(MultivaluedMap.class), testResponseEntity, cookingState, linkHeader);

		assertNotNull(targetLink);
		assertEquals("/baseuri/machines/toaster", targetLink.getHref());
		assertEquals("toaster.cooking>toaster.exists", targetLink.getTitle());
	}


	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForTargetState() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster");
		ResourceState cookingState = new ResourceState("toaster", "cooking", "/machines/toaster/cooking");

		// view the resource if the toaster is cooking (could be time remaining)
		existsState.addTransition("GET", cookingState);
		// stop the toast cooking
		cookingState.addTransition("DELETE", existsState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, cookingState, "DELETE");

		assertNotNull(targetLink);
		assertEquals("/baseuri/machines/toaster", targetLink.getHref());
		assertEquals("toaster.cooking>toaster.exists", targetLink.getTitle());
	}

	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForSelfState() {
		CollectionResourceState collectionState = new CollectionResourceState("machines", "MachineView", "/machines");

		// create machines
		collectionState.addTransition("POST", collectionState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(collectionState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, collectionState, "POST");

		assertNotNull(targetLink);
		// a target link the same as our current state equates to 205 Reset Content
		assertEquals("/baseuri/machines", targetLink.getHref());
		// we use createSelfLink under the covers so link id looks like transition to self
		assertEquals("machines.MachineView>machines.MachineView", targetLink.getTitle());
	}

	/*
	 * We return a Link if a @{link Transition} for supplied method can be found.
	 * When the target state is a pseudo final state, no link will be returned.
	 */
	@SuppressWarnings("unchecked")
	@Test
	public void testGetLinkForFinalPseudoState() {
		ResourceState existsState = new ResourceState("toaster", "exists", "/machines/toaster/{id}");
		ResourceState deletedState = new ResourceState("toaster", "cooking", null);

		// delete the toaster
		existsState.addTransition("DELETE", deletedState);
		// the entity for linkage mapping
		EntityResource<Object> testResponseEntity = new EntityResource<Object>(null);
		// initialise application state
		ResourceStateMachine stateMachine = new ResourceStateMachine(existsState);

		Link targetLink = stateMachine.getLink(mock(MultivaluedMap.class), testResponseEntity, existsState, "DELETE");

		// no target link equates to 204 No Content
		assertNull(targetLink);
	}

	@Test
	public void testStates() {
		String ENTITY_NAME = "T24CONTRACT";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
		ResourceState unauthorised = new ResourceState(ENTITY_NAME, "INAU", "unauthorised/{id}");
		ResourceState authorised = new ResourceState(ENTITY_NAME, "LIVE", "authorised/{id}");
		ResourceState reversed = new ResourceState(ENTITY_NAME, "RNAU", "reversed/{id}");
		ResourceState history = new ResourceState(ENTITY_NAME, "REVE", "history/{id}");
		ResourceState end = new ResourceState(ENTITY_NAME, "end", "{id}");
	
		begin.addTransition("PUT", unauthorised);
		
		unauthorised.addTransition("PUT", unauthorised);
		unauthorised.addTransition("PUT", authorised);
		unauthorised.addTransition("DELETE", end);
		
		authorised.addTransition("PUT", history);
		
		history.addTransition("PUT", reversed);
		
		
		ResourceStateMachine sm = new ResourceStateMachine(begin);
		assertEquals(6, sm.getStates().size());
		
		Set<ResourceState> testStates = new HashSet<ResourceState>();
		testStates.add(begin);
		testStates.add(unauthorised);
		testStates.add(authorised);
		testStates.add(reversed);
		testStates.add(history);
		testStates.add(end);
		for (ResourceState s : testStates) {
			assertTrue(sm.getStates().contains(s));
		}
		
		System.out.println(new ASTValidation().graph(sm));
	}
	
	/**
	 * Test {@link ResourceStateMachine#getStates() should return all states.}
	 */
	@Test
	public void testGetStates() {
		String ENTITY_NAME = "";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
		ResourceState exists = new ResourceState(ENTITY_NAME, "exists", "{id}");
		ResourceState end = new ResourceState(ENTITY_NAME, "end", null);
	
		begin.addTransition("PUT", exists);
		exists.addTransition("PUT", exists);
		exists.addTransition("DELETE", end);
		
		ResourceStateMachine sm = new ResourceStateMachine(begin);
		Collection<ResourceState> states = sm.getStates();
		assertEquals("Number of states", 3, states.size());
		assertTrue(states.contains(begin));
		assertTrue(states.contains(exists));
		assertTrue(states.contains(end));
	}

	@Test
	public void testGetTransitions() {
		String ENTITY_NAME = "";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
		ResourceState exists = new ResourceState(ENTITY_NAME, "exists", "{id}");
		ResourceState end = new ResourceState(ENTITY_NAME, "end", null);
	
		begin.addTransition("PUT", exists);
		exists.addTransition("PUT", exists);
		exists.addTransition("DELETE", end);
		
		ResourceStateMachine sm = new ResourceStateMachine(begin);
		Map<String,Transition> transitions = sm.getTransitionsById();
		assertEquals("Number of transistions", 3, transitions.size());
		assertNotNull(transitions.get(".begin>.exists"));
		assertNotNull(transitions.get(".exists>.exists"));
		assertNotNull(transitions.get(".exists>.end"));
	}
	
	@Test
	public void testInteractionMap() {
		String ENTITY_NAME = "";
		ResourceState begin = new ResourceState(ENTITY_NAME, "begin", "{id}");
{'fraction_non_alphanumeric': 0.11846626876469524, 'fraction_numerical': 0.0017483571471634412, 'mean_word_length': 5.619313647246608, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3234059', 'n_tokens_mistral': 5027, 'n_tokens_neox': 4623, 'n_words': 1171}