Newer
Older
AlgebraicDataflowArchitectureModel / AlgebraicDataflowArchitectureModel / src / tests / JAXRSCodeGeneratorTest.java
package tests;

import static org.junit.Assert.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.junit.Test;

import algorithms.*;
import code.ast.Annotation;
import code.ast.CompilationUnit;
import code.ast.FieldDeclaration;
import code.ast.MethodDeclaration;
import code.ast.TypeDeclaration;
import code.ast.VariableDeclaration;
import generators.CodeGeneratorFromDataFlowGraph;
import generators.DataTransferMethodAnalyzer;
import generators.JavaCodeGenerator;
import generators.JavaMethodBodyGenerator;
import generators.JavaSpecific;
import generators.JerseyCodeGenerator;
import generators.JerseyMethodBodyGenerator;
import generators.JerseySpecific;
import models.Edge;
import models.dataFlowModel.*;
import parser.*;
import parser.exceptions.ExpectedAssignment;
import parser.exceptions.ExpectedChannel;
import parser.exceptions.ExpectedChannelName;
import parser.exceptions.ExpectedColon;
import parser.exceptions.ExpectedDoubleQuotation;
import parser.exceptions.ExpectedEquals;
import parser.exceptions.ExpectedInOrOutOrRefOrSubKeyword;
import parser.exceptions.ExpectedLeftCurlyBracket;
import parser.exceptions.ExpectedRHSExpression;
import parser.exceptions.ExpectedRightBracket;
import parser.exceptions.ExpectedRightCurlyBracket;
import parser.exceptions.ExpectedStateTransition;
import parser.exceptions.WrongJsonExpression;
import parser.exceptions.WrongLHSExpression;
import parser.exceptions.WrongPathExpression;
import parser.exceptions.WrongRHSExpression;

public class JAXRSCodeGeneratorTest {
	
	@Test
	public void test() {
		testAccounts();
		testClock();
		testCustomerManagement();
		testGroupChat();
		testInventoryManagement();
		testOnlineBattleGame();
		testOnlineBattleGame2();
		testPOS();
		testSimpleTwitter();
		testVotingSystem();
		testWeatherObservationSystem();
	}
	
	private void testAccounts() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/Accounts.model", null);
			Map<String, 										// class name to
				Entry<Set<String>,								// class annotations
					  Entry<Map<String, String>,  				// field name to type
							Map<String, 						// method name to
								Entry<Set<String>,				// class annotations
									  Entry<String, 			// return type
						        			Entry<List<String>,	// arg types
						          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "List<Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("List<Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("int"),
																										 1)))),
																				 Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{uid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("String", 
																										   Map.entry(List.of("int"),
																										   1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{uid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("int"),
																											  1)))),
																				 Map.entry("changeName", Map.entry(Set.of("@Path(\"/{uid}/name\")","@PUT"),
																										 Map.entry("void", 
																										 Map.entry(List.of("int","String"),
																										 1)))),
																				 Map.entry("signup", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String"),
																									 1))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
								Map.entry(Map.ofEntries(Map.entry("name", "String")),
										  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																			  Map.entry("Map<String, Object>", 
																			  Map.entry(List.of(),
																			  1)))),
														Map.entry("getName", Map.entry(Set.of(),
																			 Map.entry("String", 
																			 Map.entry(List.of(),
																			 1)))),
														Map.entry("changeName", Map.entry(Set.of(),
																				Map.entry("void", 
																				Map.entry(List.of("int","String"),
																				1)))),
														Map.entry("Account", Map.entry(Set.of(),
																			 Map.entry("void", 
																			 Map.entry(List.of("String"),
																			 1))))))));
			
			checkStructure(generatedCode, exprectedStructure);						
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testClock() {
		try {
			// check PULL-first
			ArrayList<CompilationUnit> generatedCode = generateCode("models/Clock.model", PushPullValue.PULL);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			
			exprectedStructure.put("Hour", Map.entry(Set.of("@Path(\"/hour\")","@Component"),
													 Map.entry(Map.ofEntries(Map.entry("value", "int")),
															   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																								   Map.entry("int", 
																								   Map.entry(List.of(),
																								   1)))),
																			 Map.entry("updateFromMin", Map.entry(Set.of("@POST"),
																										Map.entry("void", 
																										Map.entry(List.of("int"),
																										1)))),
																			 Map.entry("Hour", Map.entry(Set.of(),
																							   Map.entry("void", 
																							   Map.entry(List.of("int"),
																							   1))))))));
			exprectedStructure.put("Min_ang", Map.entry(Set.of("@Path(\"/min_ang\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("client", "Client")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("double", 
																									  Map.entry(List.of(),
																									  2))))))));
			exprectedStructure.put("Hour_ang", Map.entry(Set.of("@Path(\"/hour_ang\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("client", "Client")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("double", 
																									   Map.entry(List.of(),
																									   2))))))));
			exprectedStructure.put("Min", Map.entry(Set.of("@Path(\"/min\")","@Component"),
													Map.entry(Map.ofEntries(Map.entry("value", "int"),
																			Map.entry("client", "Client")),
															  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																								  Map.entry("int", 
																								  Map.entry(List.of(),
																								  1)))),
																			Map.entry("Min", Map.entry(Set.of(),
																							 Map.entry("void", 
																							 Map.entry(List.of("int"),
																							 1)))),
																			Map.entry("tick", Map.entry(Set.of("@POST"),
																							  Map.entry("void", 
																							  Map.entry(List.of(),
																							  3))))))));
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
			
			// check PUSH-first
			generatedCode = generateCode("models/Clock.model", PushPullValue.PUSH);
			exprectedStructure.clear();
			exprectedStructure.put("Min_ang", Map.entry(Set.of("@Path(\"/min_ang\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "double")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("double", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updateFromMin", Map.entry(Set.of("@PUT"),
																										   Map.entry("void", 
																										   Map.entry(List.of("int"),
																										   1)))),
																				Map.entry("Min_ang", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("double"),
																									 1))))))));
			exprectedStructure.put("Hour_ang", Map.entry(Set.of("@Path(\"/hour_ang\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "double")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("double", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("updateFromHour", Map.entry(Set.of("@PUT"),
																											 Map.entry("void", 
																											 Map.entry(List.of("int"),
																											 1)))),
																				 Map.entry("Hour_ang", Map.entry(Set.of(),
																									   Map.entry("void", 
																									   Map.entry(List.of("double"),
																									   1))))))));
			exprectedStructure.put("Min", Map.entry(Set.of("@Path(\"/min\")","@Component"),
													Map.entry(Map.ofEntries(Map.entry("value", "int"),
																			Map.entry("client", "Client")),
															  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																								  Map.entry("int", 
																								  Map.entry(List.of(),
																								  1)))),
																			Map.entry("Min", Map.entry(Set.of(),
																							 Map.entry("void", 
																							 Map.entry(List.of("int"),
																							 1)))),
																			Map.entry("tick", Map.entry(Set.of("@POST"),
																							  Map.entry("void", 
																							  Map.entry(List.of(),
																							  5))))))));
			exprectedStructure.put("Hour", Map.entry(Set.of("@Path(\"/hour\")","@Component"),
													 Map.entry(Map.ofEntries(Map.entry("value", "int"),
																			 Map.entry("client", "Client")),
															   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																								   Map.entry("int", 
																								   Map.entry(List.of(),
																								   1)))),
																			 Map.entry("updateFromMin", Map.entry(Set.of("@POST"),
																										Map.entry("void", 
																										Map.entry(List.of("int"),
																										3)))),
																			 Map.entry("Hour", Map.entry(Set.of(),
																							   Map.entry("void", 
																							   Map.entry(List.of("int"),
																							   1))))))));
			
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testCustomerManagement() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/CustomerManagement.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Companies", Map.entry(Set.of("@Path(\"/companies\")","@Component"),
														  Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Company>")),
																	Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("Map<String, Company>", 
																										Map.entry(List.of(),
																										1)))),
																				  Map.entry("getCompany", Map.entry(Set.of(),
																										  Map.entry("Company", 
																										  Map.entry(List.of("String"),
																										  1)))),
																				  Map.entry("getAddressValue", Map.entry(Set.of("@Path(\"/{cid}/address\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											   Map.entry("String", 
																											   Map.entry(List.of("String"),
																											   1)))),
																				  Map.entry("getCompanyValue", Map.entry(Set.of("@Path(\"/{cid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											   Map.entry("Map<String, Object>", 
																											   Map.entry(List.of("String"),
																											   1)))),
																				  Map.entry("setAddress", Map.entry(Set.of("@Path(\"/{cid}/address\")","@PUT"),
																										  Map.entry("void", 
																										  Map.entry(List.of("String","String"),
																										  1)))),
																				  Map.entry("addCampany", Map.entry(Set.of("@POST"),
																										  Map.entry("void", 
																										  Map.entry(List.of("String","String"),
																										  1))))))));
			exprectedStructure.put("Customers", Map.entry(Set.of("@Path(\"/customers\")","@Component"),
														  Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Customer>")),
																	Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("Map<String, Customer>", 
																										Map.entry(List.of(),
																										1)))),
																				  Map.entry("getCustomer", Map.entry(Set.of(),
																										   Map.entry("Customer", 
																										   Map.entry(List.of("String"),
																										   1)))),
																				  Map.entry("getAddressValue", Map.entry(Set.of("@Path(\"/{uid}/address\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											   Map.entry("String", 
																											   Map.entry(List.of("String"),
																											   1)))),
																				  Map.entry("getCustomerValue", Map.entry(Set.of("@Path(\"/{uid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																												Map.entry("Map<String, Object>", 
																												Map.entry(List.of("String"),
																												1)))),
																				  Map.entry("getOrganizationValue", Map.entry(Set.of("@Path(\"/{uid}/organization\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																													Map.entry("String", 
																													Map.entry(List.of("String"),
																													1)))),
																				  Map.entry("addCustomer", Map.entry(Set.of("@POST"),
																										   Map.entry("void", 
																										   Map.entry(List.of("String","String"),
																										   1)))),
																				  Map.entry("setOrganization", Map.entry(Set.of("@Path(\"/{uid}/organization\")","@PUT"),
																											   Map.entry("void", 
																											   Map.entry(List.of("String","String"),
																											   1))))))));
			exprectedStructure.put("Customer", Map.entry(Set.of(),
														 Map.entry(Map.ofEntries(Map.entry("organization", "String"),
																				 Map.entry("client", "Client")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									   Map.entry("Map<String, Object>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getOrganization", Map.entry(Set.of(),
																											  Map.entry("String", 
																											  Map.entry(List.of(),
																											  1)))),
																				 Map.entry("getAddress", Map.entry(Set.of(),
																										 Map.entry("String", 
																										 Map.entry(List.of(),
																										 2)))),
																				 Map.entry("setOrganization", Map.entry(Set.of(),
																											  Map.entry("void", 
																											  Map.entry(List.of("String","String"),
																											  1)))),
																				 Map.entry("Customer", Map.entry(Set.of(),
																									   Map.entry("void", 
																									   Map.entry(List.of("String"),
																									   1))))))));
			exprectedStructure.put("Company", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("address", "String")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getAddress", Map.entry(Set.of(),
																										Map.entry("String", 
																										Map.entry(List.of(),
																										1)))),
																				Map.entry("setAddress", Map.entry(Set.of(),
																										Map.entry("void", 
																										Map.entry(List.of("String","String"),
																										1)))),
																				Map.entry("Company", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("String"),
																									 1))))))));
			
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testGroupChat() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/GroupChat.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Groups", Map.entry(Set.of("@Path(\"/groups\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Group>")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("Map<String, Group>", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("getGroup", Map.entry(Set.of(),
																									 Map.entry("Group", 
																									 Map.entry(List.of("String"),
																									 1)))),
																			   Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{gid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											Map.entry("List<String>", 
																											Map.entry(List.of("String"),
																											1)))),
																			   Map.entry("getMessagesValue", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											 Map.entry("List<String>", 
																											 Map.entry(List.of("String"),
																											 1)))),
																			   Map.entry("getGroupValue", Map.entry(Set.of("@Path(\"/{gid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										  Map.entry("Map<String, Object>", 
																										  Map.entry(List.of("String"),
																										  1)))),
																			   Map.entry("addGroupMember", Map.entry(Set.of("@Path(\"/{gid}/members\")","@POST"),
																										   Map.entry("void", 
																										   Map.entry(List.of("String","String"),
																										   1)))),
																			   Map.entry("postMessage", Map.entry(Set.of("@Path(\"/{gid}/messages\")","@POST"),
																										Map.entry("void", 
																										Map.entry(List.of("String","String"),
																										1)))),
																			   Map.entry("createGroup", Map.entry(Set.of("@POST"),
																										Map.entry("void", 
																										Map.entry(List.of("String"),
																										1))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("notifications", "Map<String, Boolean>")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getNotifications", Map.entry(Set.of(),
																											  Map.entry("Map<String, Boolean>", 
																											  Map.entry(List.of(),
																											  1)))),
																				Map.entry("updateNotificationsFromMessages", Map.entry(Set.of(),
																															 Map.entry("void", 
																															 Map.entry(List.of("String","String","int","List<String>","String"),
																															 1)))),
																				Map.entry("hasRead", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","String"),
																									 1)))),
																				Map.entry("Account", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("Map<String, Boolean>"),
																									 1))))))));
			exprectedStructure.put("Group", Map.entry(Set.of(),
													  Map.entry(Map.ofEntries(Map.entry("messages", "List<String>"),
																			  Map.entry("client", "Client"),
																			  Map.entry("members", "List<String>")),
																Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									Map.entry("Map<String, Object>", 
																									Map.entry(List.of(),
																									1)))),
																			  Map.entry("getMessages", Map.entry(Set.of(),
																									   Map.entry("List<String>", 
																									   Map.entry(List.of(),
																									   1)))),
																			  Map.entry("getMembers", Map.entry(Set.of(),
																									  Map.entry("List<String>", 
																									  Map.entry(List.of(),
																									  1)))),
																			  Map.entry("postMessage", Map.entry(Set.of(),
																									   Map.entry("void", 
																									   Map.entry(List.of("String","String"),
																									   6)))),
																			  Map.entry("addGroupMember", Map.entry(Set.of(),
																										  Map.entry("void", 
																										  Map.entry(List.of("String","String"),
																										  1)))),
																			  Map.entry("Group", Map.entry(Set.of(),
																								 Map.entry("void", 
																								 Map.entry(List.of("List<String>","List<String>"),
																								 2))))))));
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("Map<String, Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("String"),
																										 1)))),
																				 Map.entry("updateNotificationsFromMessages", Map.entry(Set.of("@Path(\"accounts/{v1}/notifications\")","@POST"),
																															  Map.entry("void", 
																															  Map.entry(List.of("String","String","int","List<String>","String"),
																															  1)))),
																				 Map.entry("getNotificationsValue", Map.entry(Set.of("@Path(\"/{v1}/notifications\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																													Map.entry("Map<String, Boolean>", 
																													Map.entry(List.of("String"),
																													1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{v1}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("String"),
																											  1)))),
																				 Map.entry("hasRead", Map.entry(Set.of("@Path(\"/{aid}/notifications\")","@DELETE"),
																									  Map.entry("void", 
																									  Map.entry(List.of("String","String"),
																									  1)))),
																				 Map.entry("signUp", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String"),
																									 1))))))));
			
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testInventoryManagement() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/InventoryManagement.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("InventoryElement", Map.entry(Set.of(),
																 Map.entry(Map.ofEntries(Map.entry("count", "int")),
																		   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																											   Map.entry("Map<String, Object>", 
																											   Map.entry(List.of(),
																											   1)))),
																						 Map.entry("getCount", Map.entry(Set.of(),
																											   Map.entry("int", 
																											   Map.entry(List.of(),
																											   1)))),
																						 Map.entry("receiveOrShip", Map.entry(Set.of(),
																													Map.entry("void", 
																													Map.entry(List.of("String","int"),
																													1)))),
																						 Map.entry("InventoryElement", Map.entry(Set.of(),
																													   Map.entry("void", 
																													   Map.entry(List.of("int"),
																													   1))))))));
			exprectedStructure.put("Inventory", Map.entry(Set.of("@Path(\"/inventory\")","@Component"),
														  Map.entry(Map.ofEntries(Map.entry("value", "Map<String, InventoryElement>")),
																	Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("Map<String, InventoryElement>", 
																										Map.entry(List.of(),
																										1)))),
																				  Map.entry("getInventoryElement", Map.entry(Set.of(),
																												   Map.entry("InventoryElement", 
																												   Map.entry(List.of("String"),
																												   1)))),
																				  Map.entry("getInventoryElementValue", Map.entry(Set.of("@Path(\"/{itemId}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																														Map.entry("Map<String, Object>", 
																														Map.entry(List.of("String"),
																														1)))),
																				  Map.entry("getCountValue", Map.entry(Set.of("@Path(\"/{itemId}/count\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											 Map.entry("int", 
																											 Map.entry(List.of("String"),
																											 1)))),
																				  Map.entry("registerItem", Map.entry(Set.of("@POST"),
																											Map.entry("void", 
																											Map.entry(List.of("String","int","String"),
																											1)))),
																				  Map.entry("receiveOrShip", Map.entry(Set.of("@Path(\"/{itemId}/count\")","@POST"),
																											 Map.entry("void", 
																											 Map.entry(List.of("String","int"),
																											 1))))))));
			
			checkStructure(generatedCode, exprectedStructure);						
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testOnlineBattleGame() {
		try {
			// check PULL-first
			ArrayList<CompilationUnit> generatedCode = generateCode("models/OnlineBattleGame.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"),
													  Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Room>")),
																Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									Map.entry("Map<String, Room>", 
																									Map.entry(List.of(),
																									1)))),
																			  Map.entry("getRoom", Map.entry(Set.of(),
																								   Map.entry("Room", 
																								   Map.entry(List.of("String"),
																								   1)))),
																			  Map.entry("getBlue_idValue", Map.entry(Set.of("@Path(\"/{rid}/blue_id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("String", 
																										   Map.entry(List.of("String"),
																										   1)))),
																			  Map.entry("getRed_nameValue", Map.entry(Set.of("@Path(\"/{rid}/red_name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											Map.entry("String", 
																											Map.entry(List.of("String"),
																											1)))),
																			  Map.entry("getBlue_nameValue", Map.entry(Set.of("@Path(\"/{rid}/blue_name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											 Map.entry("String", 
																											 Map.entry(List.of("String"),
																											 1)))),
																			  Map.entry("getRed_idValue", Map.entry(Set.of("@Path(\"/{rid}/red_id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										  Map.entry("String", 
																										  Map.entry(List.of("String"),
																										  1)))),
																			  Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("Map<String, Object>", 
																										Map.entry(List.of("String"),
																										1)))),
																			  Map.entry("changeBlueId", Map.entry(Set.of("@Path(\"/{rid}/blue_id\")","@PUT"),
																										Map.entry("void", 
																										Map.entry(List.of("String","String"),
																										1)))),
																			  Map.entry("createRoom", Map.entry(Set.of("@POST"),
																									  Map.entry("void", 
																									  Map.entry(List.of("String","String","String"),
																									  1)))),
																			  Map.entry("changeRedId", Map.entry(Set.of("@Path(\"/{rid}/red_id\")","@PUT"),
																									   Map.entry("void", 
																									   Map.entry(List.of("String","String"),
																									   1))))))));
			exprectedStructure.put("Room", Map.entry(Set.of(),
													 Map.entry(Map.ofEntries(Map.entry("blue_id", "String"),
																			 Map.entry("red_id", "String"),
																			 Map.entry("client", "Client")),
															   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																								   Map.entry("Map<String, Object>", 
																								   Map.entry(List.of(),
																								   1)))),
																			 Map.entry("getBlue_id", Map.entry(Set.of(),
																									 Map.entry("String", 
																									 Map.entry(List.of(),
																									 1)))),
																			 Map.entry("getRed_id", Map.entry(Set.of(),
																									Map.entry("String", 
																									Map.entry(List.of(),
																									1)))),
																			 Map.entry("getRed_name", Map.entry(Set.of(),
																									  Map.entry("String", 
																									  Map.entry(List.of(),
																									  2)))),
																			 Map.entry("getBlue_name", Map.entry(Set.of(),
																									   Map.entry("String", 
																									   Map.entry(List.of(),
																									   2)))),
																			 Map.entry("changeRedId", Map.entry(Set.of(),
																									  Map.entry("void", 
																									  Map.entry(List.of("String","String"),
																									  1)))),
																			 Map.entry("changeBlueId", Map.entry(Set.of(),
																									   Map.entry("void", 
																									   Map.entry(List.of("String","String"),
																									   1)))),
																			 Map.entry("Room", Map.entry(Set.of(),
																							   Map.entry("void", 
																							   Map.entry(List.of("String","String"),
																							   2))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("name", "String")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getName", Map.entry(Set.of(),
																									 Map.entry("String", 
																									 Map.entry(List.of(),
																									 1)))),
																				Map.entry("changeName", Map.entry(Set.of(),
																										Map.entry("void", 
																										Map.entry(List.of("String","String"),
																										1)))),
																				Map.entry("Account", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("String"),
																									 1))))))));
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("Map<String, Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("String"),
																										 1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{aid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("String"),
																											  1)))),
																				 Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{aid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("String", 
																										   Map.entry(List.of("String"),
																										   1)))),
																				 Map.entry("signUp", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","String"),
																									 1)))),
																				 Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"),
																										 Map.entry("void", 
																										 Map.entry(List.of("String","String"),
																										 1))))))));
			
			checkStructure(generatedCode, exprectedStructure);			
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	
	private void testOnlineBattleGame2() {
		try {
			// check PULL-first
			ArrayList<CompilationUnit> generatedCode = generateCode("models/OnlineBattleGame2.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Rooms", Map.entry(Set.of("@Path(\"/rooms\")","@Component"),
													  Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Room>")),
																Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									Map.entry("Map<String, Room>", 
																									Map.entry(List.of(),
																									1)))),
																			  Map.entry("getRoom", Map.entry(Set.of(),
																								   Map.entry("Room", 
																								   Map.entry(List.of("String"),
																								   1)))),
																			  Map.entry("getIdValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/id\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("String", 
																									  Map.entry(List.of("String","int"),
																									  1)))),
																			  Map.entry("getBattleValue", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										  Map.entry("boolean", 
																										  Map.entry(List.of("String"),
																										  1)))),
																			  Map.entry("getRoomValue", Map.entry(Set.of("@Path(\"/{rid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("Map<String, Object>", 
																										Map.entry(List.of("String"),
																										1)))),
																			  Map.entry("getMemberValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										  Map.entry("Map<String, Object>", 
																										  Map.entry(List.of("String","int"),
																										  1)))),
																			  Map.entry("getMembersValue", Map.entry(Set.of("@Path(\"/{rid}/members\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("List<Member>", 
																										   Map.entry(List.of("String"),
																										   1)))),
																			  Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{rid}/members/{mno}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										Map.entry("String", 
																										Map.entry(List.of("String","int"),
																										1)))),
																			  Map.entry("battle", Map.entry(Set.of("@Path(\"/{rid}/battle\")","@PUT"),
																								  Map.entry("void", 
																								  Map.entry(List.of("String","boolean"),
																								  1)))),
																			  Map.entry("addRoomMember", Map.entry(Set.of("@Path(\"/{rid}/members\")","@POST"),
																										 Map.entry("void", 
																										 Map.entry(List.of("String","String"),
																										 1)))),
																			  Map.entry("createRoom", Map.entry(Set.of("@POST"),
																									  Map.entry("void", 
																									  Map.entry(List.of("String"),
																									  1))))))));
			exprectedStructure.put("Member", Map.entry(Set.of(),
													   Map.entry(Map.ofEntries(Map.entry("id", "String"),
																			   Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									 Map.entry("Map<String, Object>", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("getId", Map.entry(Set.of(),
																								  Map.entry("String", 
																								  Map.entry(List.of(),
																								  1)))),
																			   Map.entry("getName", Map.entry(Set.of(),
																									Map.entry("String", 
																									Map.entry(List.of(),
																									2)))),
																			   Map.entry("Member", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("String"),
																								   1))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("name", "String"),
																				Map.entry("point", "int")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getName", Map.entry(Set.of(),
																									 Map.entry("String", 
																									 Map.entry(List.of(),
																									 1)))),
																				Map.entry("getPoint", Map.entry(Set.of(),
																									  Map.entry("int", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updatePointFromBattle", Map.entry(Set.of(),
																												   Map.entry("void", 
																												   Map.entry(List.of("String","String","int","boolean","String"),
																												   1)))),
																				Map.entry("changeName", Map.entry(Set.of(),
																										Map.entry("void", 
																										Map.entry(List.of("String","String"),
																										1)))),
																				Map.entry("Account", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","int"),
																									 2))))))));
			exprectedStructure.put("Room", Map.entry(Set.of(),
													 Map.entry(Map.ofEntries(Map.entry("members", "Members"),
																			 Map.entry("battle", "boolean"),
																			 Map.entry("client", "Client")),
															   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																								   Map.entry("Map<String, Object>", 
																								   Map.entry(List.of(),
																								   1)))),
																			 Map.entry("getMembers", Map.entry(Set.of(),
																									 Map.entry("Members", 
																									 Map.entry(List.of(),
																									 1)))),
																			 Map.entry("getBattle", Map.entry(Set.of(),
																									Map.entry("boolean", 
																									Map.entry(List.of(),
																									1)))),
																			 Map.entry("battle", Map.entry(Set.of(),
																								 Map.entry("void", 
																								 Map.entry(List.of("String","boolean"),
																								 6)))),
																			 Map.entry("Room", Map.entry(Set.of(),
																							   Map.entry("void", 
																							   Map.entry(List.of("boolean"),
																							   1))))))));
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("Map<String, Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("String"),
																										 1)))),
																				 Map.entry("updatePointFromBattle", Map.entry(Set.of("@Path(\"accounts/{mid}/point\")","@POST"),
																													Map.entry("void", 
																													Map.entry(List.of("String","String","int","boolean","String"),
																													1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{mid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("String"),
																											  1)))),
																				 Map.entry("getNameValue", Map.entry(Set.of("@Path(\"/{mid}/name\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("String", 
																										   Map.entry(List.of("String"),
																										   1)))),
																				 Map.entry("getPointValue", Map.entry(Set.of("@Path(\"/{mid}/point\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											Map.entry("int", 
																											Map.entry(List.of("String"),
																											1)))),
																				 Map.entry("signUp", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","String"),
																									 1)))),
																				 Map.entry("changeName", Map.entry(Set.of("@Path(\"/{aid}/name\")","@PUT"),
																										 Map.entry("void", 
																										 Map.entry(List.of("String","String"),
																										 1))))))));
			exprectedStructure.put("Members", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("value", "List<Member>")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("List<Member>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getMember", Map.entry(Set.of(),
																									   Map.entry("Member", 
																									   Map.entry(List.of("int"),
																									   1)))),
																				Map.entry("addRoomMember", Map.entry(Set.of(),
																										   Map.entry("void", 
																										   Map.entry(List.of("String","String"),
																										   1))))))));
			
			checkStructure(generatedCode, exprectedStructure);			
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testPOS() {
		try {
			// check PULL-first
			ArrayList<CompilationUnit> generatedCode = generateCode("models/POS.model", PushPullValue.PULL);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Points", Map.entry(Set.of("@Path(\"/points\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("int", 
																									 Map.entry(List.of(),
																									 2))))))));
			exprectedStructure.put("History", Map.entry(Set.of("@Path(\"/history\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "List<Integer>")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("List<Integer>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updateFromPayment", Map.entry(Set.of("@POST"),
																											   Map.entry("void", 
																											   Map.entry(List.of("int"),
																											   1)))),
																				Map.entry("History", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("List<Integer>"),
																									 1))))))));
			exprectedStructure.put("Payment", Map.entry(Set.of("@Path(\"/payment\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "int"),
																				Map.entry("client", "Client")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("int", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("Payment", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("int"),
																									 1)))),
																				Map.entry("purchase", Map.entry(Set.of("@PUT"),
																									  Map.entry("void", 
																									  Map.entry(List.of("int"),
																									  3))))))));
			exprectedStructure.put("Total", Map.entry(Set.of("@Path(\"/total\")","@Component"),
													  Map.entry(Map.ofEntries(Map.entry("client", "Client")),
																Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									Map.entry("int", 
																									Map.entry(List.of(),
																									2))))))));
			
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
			
			// check PUSH-first
			generatedCode = generateCode("models/POS.model", PushPullValue.PUSH);
			exprectedStructure.clear();
			exprectedStructure.put("Total", Map.entry(Set.of("@Path(\"/total\")","@Component"),
													  Map.entry(Map.ofEntries(Map.entry("value", "int")),
																Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									Map.entry("int", 
																									Map.entry(List.of(),
																									1)))),
																			  Map.entry("updateFromHistory", Map.entry(Set.of("@PUT"),
																											 Map.entry("void", 
																											 Map.entry(List.of("List<Integer>"),
																											 1)))),
																			  Map.entry("Total", Map.entry(Set.of(),
																								 Map.entry("void", 
																								 Map.entry(List.of("int"),
																								 1))))))));
			exprectedStructure.put("History", Map.entry(Set.of("@Path(\"/history\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "List<Integer>"),
																				Map.entry("client", "Client")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("List<Integer>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updateFromPayment", Map.entry(Set.of("@POST"),
																											   Map.entry("void", 
																											   Map.entry(List.of("int"),
																											   3)))),
																				Map.entry("History", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("List<Integer>"),
																									 1))))))));
			exprectedStructure.put("Points", Map.entry(Set.of("@Path(\"/points\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "int")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("int", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("updateFromPayment", Map.entry(Set.of("@PUT"),
																											  Map.entry("void", 
																											  Map.entry(List.of("int"),
																											  1)))),
																			   Map.entry("Points", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("int"),
																								   1))))))));
			exprectedStructure.put("Payment", Map.entry(Set.of("@Path(\"/payment\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "int"),
																				Map.entry("client", "Client")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("int", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("Payment", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("int"),
																									 1)))),
																				Map.entry("purchase", Map.entry(Set.of("@PUT"),
																									  Map.entry("void", 
																									  Map.entry(List.of("int"),
																									  5))))))));
			
			checkStructure(generatedCode, exprectedStructure);						
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testSimpleTwitter() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/SimpleTwitter.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("Map<String, Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("String"),
																										 1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{accountId}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("String"),
																											  1)))),
																				 Map.entry("getTweetsValue", Map.entry(Set.of("@Path(\"/{accountId}/tweets\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											 Map.entry("List<String>", 
																											 Map.entry(List.of("String"),
																											 1)))),
																				 Map.entry("tweet", Map.entry(Set.of("@Path(\"/{accountId}/tweets\")","@POST"),
																									Map.entry("void", 
																									Map.entry(List.of("String","String"),
																									1)))),
																				 Map.entry("signUp", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","String"),
																									 1))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("tweets", "List<String>")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getTweets", Map.entry(Set.of(),
																									   Map.entry("List<String>", 
																									   Map.entry(List.of(),
																									   1)))),
																				Map.entry("tweet", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("String","String"),
																								   1)))),
																				Map.entry("Account", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("List<String>"),
																									 1))))))));

			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
		
	private void testVotingSystem() {
		try {
			ArrayList<CompilationUnit> generatedCode = generateCode("models/VotingSystem.model", null);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Counts", Map.entry(Set.of("@Path(\"/counts\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Object>"),
																			   Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("Map<String, Object>", 
																									 Map.entry(List.of(),
																									 8)))),
																			   Map.entry("Counts", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("Map<String, Object>"),
																								   1))))))));
			exprectedStructure.put("Account", Map.entry(Set.of(),
														Map.entry(Map.ofEntries(Map.entry("vote", "String")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of(),
																									  Map.entry("Map<String, Object>", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("getVote", Map.entry(Set.of(),
																									 Map.entry("String", 
																									 Map.entry(List.of(),
																									 1)))),
																				Map.entry("cast", Map.entry(Set.of(),
																								  Map.entry("void", 
																								  Map.entry(List.of("String","String"),
																								  1)))),
																				Map.entry("Account", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("String"),
																									 1))))))));
			exprectedStructure.put("Accounts", Map.entry(Set.of("@Path(\"/accounts\")","@Component"),
														 Map.entry(Map.ofEntries(Map.entry("value", "Map<String, Account>")),
																   Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									   Map.entry("Map<String, Account>", 
																									   Map.entry(List.of(),
																									   1)))),
																				 Map.entry("getAccount", Map.entry(Set.of(),
																										 Map.entry("Account", 
																										 Map.entry(List.of("String"),
																										 1)))),
																				 Map.entry("getAccountValue", Map.entry(Set.of("@Path(\"/{aid}\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																											  Map.entry("Map<String, Object>", 
																											  Map.entry(List.of("String"),
																											  1)))),
																				 Map.entry("getVoteValue", Map.entry(Set.of("@Path(\"/{aid}/vote\")","@Produces(MediaType.APPLICATION_JSON)","@GET"),
																										   Map.entry("String", 
																										   Map.entry(List.of("String"),
																										   1)))),
																				 Map.entry("signUp", Map.entry(Set.of("@POST"),
																									 Map.entry("void", 
																									 Map.entry(List.of("String","String"),
																									 1)))),
																				 Map.entry("cast", Map.entry(Set.of("@Path(\"/{aid}/vote\")","@PUT"),
																								   Map.entry("void", 
																								   Map.entry(List.of("String","String"),
																								   1))))))));

			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}
	
	private void testWeatherObservationSystem() {
		try {
			// check PULL-first
			ArrayList<CompilationUnit> generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PULL);
			Map<String, 										// class name to
			Entry<Set<String>,								// class annotations
				  Entry<Map<String, String>,  				// field name to type
						Map<String, 						// method name to
							Entry<Set<String>,				// class annotations
								  Entry<String, 			// return type
					        			Entry<List<String>,	// arg types
					          				Integer>>>>>>>	// lines of code
				exprectedStructure = new HashMap<>();
			exprectedStructure.put("Highest", Map.entry(Set.of("@Path(\"/highest\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "double")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("double", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updateFromTemp_f", Map.entry(Set.of("@POST"),
																											  Map.entry("void", 
																											  Map.entry(List.of("double"),
																											  1)))),
																				Map.entry("Highest", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("double"),
																									 1)))),
																				Map.entry("reset", Map.entry(Set.of("@PUT"),
																								   Map.entry("void", 
																								   Map.entry(List.of("double"),
																								   1))))))));
			exprectedStructure.put("Temp_c", Map.entry(Set.of("@Path(\"/temp_c\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("double", 
																									 Map.entry(List.of(),
																									 2))))))));
			exprectedStructure.put("Temp_f", Map.entry(Set.of("@Path(\"/temp_f\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "double"),
																			   Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("double", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("Temp_f", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("double"),
																								   1)))),
																			   Map.entry("observe", Map.entry(Set.of("@PUT"),
																									Map.entry("void", 
																									Map.entry(List.of("double"),
																									3))))))));
			
			checkStructure(generatedCode, exprectedStructure);
//			generateCheckCode(generatedCode);
			
			// check PUSH-first
			generatedCode = generateCode("models/WeatherObservationSystem.model", PushPullValue.PUSH);
			exprectedStructure.clear();
			exprectedStructure.put("Temp_c", Map.entry(Set.of("@Path(\"/temp_c\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "double")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("double", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("updateFromTemp_f", Map.entry(Set.of("@PUT"),
																											 Map.entry("void", 
																											 Map.entry(List.of("double"),
																											 1)))),
																			   Map.entry("Temp_c", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("double"),
																								   1))))))));
			exprectedStructure.put("Temp_f", Map.entry(Set.of("@Path(\"/temp_f\")","@Component"),
													   Map.entry(Map.ofEntries(Map.entry("value", "double"),
																			   Map.entry("client", "Client")),
																 Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									 Map.entry("double", 
																									 Map.entry(List.of(),
																									 1)))),
																			   Map.entry("Temp_f", Map.entry(Set.of(),
																								   Map.entry("void", 
																								   Map.entry(List.of("double"),
																								   1)))),
																			   Map.entry("observe", Map.entry(Set.of("@PUT"),
																									Map.entry("void", 
																									Map.entry(List.of("double"),
																									5))))))));
			exprectedStructure.put("Highest", Map.entry(Set.of("@Path(\"/highest\")","@Component"),
														Map.entry(Map.ofEntries(Map.entry("value", "double")),
																  Map.ofEntries(Map.entry("getValue", Map.entry(Set.of("@Produces(MediaType.APPLICATION_JSON)","@GET"),
																									  Map.entry("double", 
																									  Map.entry(List.of(),
																									  1)))),
																				Map.entry("updateFromTemp_f", Map.entry(Set.of("@POST"),
																											  Map.entry("void", 
																											  Map.entry(List.of("double"),
																											  1)))),
																				Map.entry("Highest", Map.entry(Set.of(),
																									 Map.entry("void", 
																									 Map.entry(List.of("double"),
																									 1)))),
																				Map.entry("reset", Map.entry(Set.of("@PUT"),
																								   Map.entry("void", 
																								   Map.entry(List.of("double"),
																								   1))))))));
			
			checkStructure(generatedCode, exprectedStructure);			
//			generateCheckCode(generatedCode);
		} catch (FileNotFoundException 
				| ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword
				| ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression
				| WrongRHSExpression | ExpectedRightBracket | ExpectedAssignment | ExpectedRightCurlyBracket 
				| WrongPathExpression | WrongJsonExpression | ExpectedColon | ExpectedDoubleQuotation e) {
			e.printStackTrace();
		}
	}

	private ArrayList<CompilationUnit> generateCode(String fileName, PushPullValue pushPullValue) throws FileNotFoundException, 
					ExpectedRightBracket, ExpectedChannel, ExpectedChannelName, ExpectedLeftCurlyBracket, ExpectedRightCurlyBracket, ExpectedInOrOutOrRefOrSubKeyword, 
					ExpectedStateTransition, ExpectedEquals, ExpectedRHSExpression, WrongLHSExpression, WrongRHSExpression, ExpectedAssignment, 
					WrongPathExpression, WrongJsonExpression, ExpectedColon, ExpectedDoubleQuotation {
		File file = new File(fileName);
		Parser parser = new Parser(new BufferedReader(new FileReader(file)));
		DataTransferModel model;
		model = parser.doParse();
		DataFlowGraph graph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model);
		DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(graph);
		if (pushPullValue != null) {
			// Select a specified push/pull transfer method if possible.
			for (Edge e : graph.getEdges()) {
				if (!((DataFlowEdge) e).isChannelToResource() && ((DataFlowEdge) e).getAttribute() instanceof PushPullAttribute) {
					PushPullAttribute ppat = (PushPullAttribute) ((DataFlowEdge) e).getAttribute();
					ppat.selectOption(pushPullValue);
				}
			}
		}
		TypeInference.infer(model);
		DataTransferMethodAnalyzer.decideToStoreResourceStates(graph);
		ArrayList<CompilationUnit> codetree = JerseyMethodBodyGenerator.doGenerate(graph, model, JerseyCodeGenerator.doGenerate(graph, model));
//		ArrayList<CompilationUnit> codetree = new CodeGeneratorFromDataFlowGraph().generateCode(model, graph, new JerseySpecific(), new JavaSpecific());
		return codetree;
	}

	private void checkStructure(ArrayList<CompilationUnit> generatedCode,
			Map<String, Entry<Set<String>, Entry<Map<String, String>, Map<String, Entry<Set<String>, Entry<String, Entry<List<String>, Integer>>>>>>> exprectedStructure) {
		for (var classEnt: exprectedStructure.entrySet()) {
			String expectedClassName = classEnt.getKey();
			Entry<Set<String>, Entry<Map<String, String>, Map<String, Entry<Set<String>, Entry<String, Entry<List<String>, Integer>>>>>> expectedClassInfo = classEnt.getValue();
			TypeDeclaration generatedClass = null; 
			for (CompilationUnit cu: generatedCode) {
				for (TypeDeclaration type: cu.types()) {
					if (type.getTypeName().equals(expectedClassName)) {
						generatedClass = type;
						break;
					}
				}
			}
			assertNotNull(generatedClass);
			
			Set<String> expectedClassAnnotations = expectedClassInfo.getKey();
			for (String expectedAnnotation: expectedClassAnnotations) {
				boolean existsAnnotation = false;
				for (Annotation generatedAnnotation: generatedClass.getAnnotations()) {
					if (expectedAnnotation.equals(generatedAnnotation.toString())) {
						existsAnnotation = true;
					}
				}
				assertTrue(existsAnnotation);
			}
			Entry<Map<String, String>, Map<String, Entry<Set<String>, Entry<String, Entry<List<String>, Integer>>>>> expectedClassStructure = expectedClassInfo.getValue();
			Map<String, String> exprectedFields = expectedClassStructure.getKey();
			Map<String, Entry<Set<String>, Entry<String, Entry<List<String>, Integer>>>> exprectedMethods = expectedClassStructure.getValue();
			
			for (String expectedFieldName: exprectedFields.keySet()) {
				FieldDeclaration generatedField = null;
				for (FieldDeclaration field: generatedClass.getFields()) {
					if (field.getName().equals(expectedFieldName)) {
						generatedField = field;
						break;
					}
				}
				assertNotNull(generatedField);
				
				String expectedFieldType = exprectedFields.get(expectedFieldName);
				if (expectedFieldType.equals("void")) {
					assertNull(generatedField.getType());
				} else {
					assertEquals(expectedFieldType, generatedField.getType().getInterfaceTypeName());
				}
			}
			
			for (String expectedMethodName: exprectedMethods.keySet()) {
				MethodDeclaration generatedMethod= null;
				for (MethodDeclaration method: generatedClass.getMethods()) {
					if (method.getName().equals(expectedMethodName)) {
						generatedMethod = method;
						break;
					}
				}
				assertNotNull(generatedMethod);
				
				Entry<Set<String>, Entry<String, Entry<List<String>, Integer>>> expectedMethodInfo = exprectedMethods.get(expectedMethodName);
				Set<String> expectedMethodAnnotations = expectedMethodInfo.getKey();
				for (String expectedAnnotation: expectedMethodAnnotations) {
					boolean existsAnnotation = false;
					for (Annotation generatedAnnotation: generatedMethod.getAnnotations()) {
						if (expectedAnnotation.replaceAll("\\{.*\\}", "\\{\\}").equals(generatedAnnotation.toString().replaceAll("\\{.*\\}", "\\{\\}"))) {
							existsAnnotation = true;
						}
					}
					assertTrue(existsAnnotation);
				}
				Entry<String, Entry<List<String>, Integer>> expectedMethodSignature = expectedMethodInfo.getValue();
				String expectedReturnType = expectedMethodSignature.getKey();
				if (expectedReturnType.equals("void")) {
					if (generatedMethod.getReturnType() != null) {
						assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName());
					} else {
						assertNull(generatedMethod.getReturnType());
					}
				} else {
					assertEquals(expectedReturnType, generatedMethod.getReturnType().getInterfaceTypeName());
				}
				Entry<List<String>, Integer> expectedMethodInfo2 = expectedMethodSignature.getValue();
				List<String> expectedArgTypes = expectedMethodInfo2.getKey();
				for (String expectedArgType: expectedArgTypes) {
					boolean existsArg = false;
					for (VariableDeclaration var: generatedMethod.getParameters()) {
						if (expectedArgType.equals(var.getType().getInterfaceTypeName())) {
							existsArg = true;
						}
					}
					assertTrue(existsArg);
				}
				int expectedLinesOfCode = expectedMethodInfo2.getValue();
				assertEquals(expectedLinesOfCode, generatedMethod.getBody().getStatements().size());
			}
		}
	}

	private void generateCheckCode(ArrayList<CompilationUnit> generatedCode) {
//			exprectedStructure.put("Main", Map.entry(Set.of(),
//													 Map.entry(Map.ofEntries(Map.entry("history", "History"),
//																			 Map.entry("total", "Total"),
//																			 Map.entry("payment", "Payment"),
//																			 Map.entry("points", "Points")), 
//															   Map.ofEntries(Map.entry("Main", Map.entry(Set.of(),
//																							   Map.entry("void", 
//																							   Map.entry(List.of(), 
//																										 4)))),
//																			 Map.entry("getHistory", Map.entry(Set.of(),
//																									 Map.entry("List",
//																									 Map.entry(List.of(),
//																											   1)))),
//																			 Map.entry("getTotal", Map.entry(Set.of(),
//																								   Map.entry("int",
//																								   Map.entry(List.of(),
//																											 1)))),
//																			 Map.entry("getPayment", Map.entry(Set.of(),
//																									 Map.entry("int",
//																									 Map.entry(List.of(),
//																											   1)))),
//																			 Map.entry("purchase", Map.entry(Set.of(),
//																								   Map.entry("void",
//																								   Map.entry(List.of("int"),
//																											 1)))),
//																			 Map.entry("getPoints", Map.entry(Set.of(),
//																									Map.entry("int",
//																									Map.entry(List.of(),
//																											  1))))))));
		for (CompilationUnit cu: generatedCode) {
			for (TypeDeclaration type: cu.types()) {
				Collection<Annotation> annotations = type.getAnnotations();
				List<FieldDeclaration> fields = type.getFields();
				List<MethodDeclaration> methods = type.getMethods();
				// class annotations
				if (annotations.size() == 0) {
					System.out.println("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Set.of(),");
				} else {
					System.out.print("\t\t\texprectedStructure.put(\"" + type.getTypeName() + "\", Map.entry(Set.of(");
					String delim = "";
					for (Annotation annotation: annotations) {
						System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\"");
						delim = ",";
					}
					System.out.println("),");
				}
				// fields
				System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t");
				for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) {
					System.out.print("\t");
				}
				for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) {
					System.out.print(" ");
				}
				if (fields.size() == 0) {
					System.out.println("Map.entry(Map.ofEntries(),");
				} else if (fields.size() == 1) {
					FieldDeclaration field = fields.get(0);
					System.out.println("Map.entry(Map.ofEntries(Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\")),");
				} else {
					int i = 0;
					for (FieldDeclaration field: fields) {
						if (i == 0) {
							System.out.println("Map.entry(Map.ofEntries(Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),");
						} else {
							System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
							for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) {
								System.out.print("\t");
							}
							for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) {
								System.out.print(" ");
							}
							if (i < fields.size() - 1) {
								System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\"),");
							} else {
								System.out.println("Map.entry(\"" + field.getName() + "\", \"" + field.getType().getInterfaceTypeName() + "\")),");
							}
						}
						i++;
					}
				}
				// methods
				if (methods.size() == 0) {
					System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
					for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) {
						System.out.print("\t");
					}
					for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) {
						System.out.print(" ");
					}
					System.out.println("Map.ofEntries())));");
				} else {
					int i = 0;
					for (MethodDeclaration method: methods) {
						// method name and method annotations
						if (i == 0) {
							System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
							for (int j = 0; j < (type.getTypeName().length() + 3) / 4; j++) {
								System.out.print("\t");
							}
							for (int j = 0; j < (type.getTypeName().length() + 3) % 4; j++) {
								System.out.print(" ");
							}
							Collection<Annotation> methodAnnotations = method.getAnnotations();
							if (methodAnnotations.size() == 0) {
								System.out.println("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(),");
							} else {
								System.out.print("Map.ofEntries(Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(");
								String delim = "";
								for (Annotation annotation: methodAnnotations) {
									System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\"");
									delim = ",";
								}
								System.out.println("),");
							}
						} else {
							System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
							for (int j = 0; j < (type.getTypeName().length() + 1) / 4; j++) {
								System.out.print("\t");
							}
							for (int j = 0; j < (type.getTypeName().length() + 1) % 4; j++) {
								System.out.print(" ");
							}
							Collection<Annotation> methodAnnotations = method.getAnnotations();
							if (methodAnnotations.size() == 0) {
								System.out.println("Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(),");
							} else {
								System.out.print("Map.entry(\"" + method.getName() + "\", Map.entry(Set.of(");
								String delim = "";
								for (Annotation annotation: methodAnnotations) {
									System.out.print(delim + "\"" + annotation.toString().replace("\"", "\\\"") + "\"");
									delim = ",";
								}
								System.out.println("),");
							}
						}
						// return type
						System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) {
							System.out.print("\t");
						}
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) {
							System.out.print(" ");
						}
						if (method.getReturnType() == null) {
							System.out.println("Map.entry(\"void\", ");
						} else {
							System.out.println("Map.entry(\"" + method.getReturnType().getInterfaceTypeName() + "\", ");
						}
						// method parameters
						System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) {
							System.out.print("\t");
						}
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) {
							System.out.print(" ");
						}
						if (method.getParameters() == null || method.getParameters().size() == 0) {
							System.out.println("Map.entry(List.of(),");
						} else {
							System.out.print("Map.entry(List.of(");
							String delim = "";
							for (VariableDeclaration arg: method.getParameters()) {
								System.out.print(delim + "\"" + arg.getType().getInterfaceTypeName() + "\"");
								delim = ",";
							}
							System.out.println("),");
						}
						// method lines of code
						System.out.print("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t");
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) / 4; j++) {
							System.out.print("\t");
						}
						for (int j = 0; j < (type.getTypeName().length() + method.getName().length() + 3) % 4; j++) {
							System.out.print(" ");
						}
						if (i < methods.size() - 1) {
							System.out.println("" + method.getBody().getStatements().size() + ")))),");
						} else {
							System.out.println("" + method.getBody().getStatements().size() + "))))))));");
						}
						i++;
					}
				}
			}
		}
	}
}