// Path: src/main/java/inference/Substitution.java
// public class Substitution extends Substitutable<Substitution> {
//     private HashMap<TVariable, Type> subs = new HashMap<>();
// 
//     public Substitution() {}
// 
//     public Substitution(TVariable variable, Type type) {
//         subs.put(variable, type);
//     }
// 
//     private Substitution(Substitution previous) {
//         subs.putAll(previous.subs);
//     }
// 
//     public Substitution(List<TVariable> vars, List<Type> substitute) {
//         if(vars.size() != substitute.size())
//             throw new IllegalArgumentException("Number of variables have to match number of types");
// 
//         for (int i = 0; i < vars.size(); i++) subs.put(vars.get(i), substitute.get(i));
//     }
// 
//     public List<TVariable> variables() {
//         return new LinkedList<>(subs.keySet());
//     }
// 
//     public Type substituteOf(TVariable var) {
//         return subs.get(var);
//     }
// 
//     public Substitution composeWith(Substitution sub) {
//         Substitution substituted = new Substitution(sub);
//         substituted.apply(this);
//         subs.putAll(substituted.subs);
//         return this;
//     }
// 
//     @Override
//     public HashSet<TVariable> ftv() {
//         HashSet<TVariable> freeVars = new HashSet<>();
//         for (TVariable var : variables()) freeVars.addAll(substituteOf(var).ftv());
//         return freeVars;
//     }
// 
//     @Override
//     public Substitution substitute(TVariable var, Type t) {
//         for (TVariable variable : variables())
//             subs.replace(variable, substituteOf(variable).substitute(var, t));
//         return this;
//     }
// 
//     @Override
//     public String toString() {
//         return subs.toString();
//     }
// 
//     @Override
//     public Substitution identity() {
//         return this;
//     }
// }
// 
// Path: src/main/java/types/TVariable.java
// public static TVariable variable(String name) {
//     TVariable var = new TVariable(name);
//     if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//     return var;
// }
// 
// Path: src/main/java/types/TVariable.java
// public static List<TVariable> variables(String... names) {
//     List<TVariable> variables = new LinkedList<>();
//     for (String name : names) variables.add(new TVariable(name));
//     return variables;
// }


import inference.Substitution;
import org.junit.Test;
import java.util.*;
import static org.junit.Assert.assertEquals;
import static types.TVariable.variable;
import static types.TVariable.variables;
package types;




/**
 * Created by valentin on 20/10/2016.
 */
public class TVariableTest {
    private static final String name = "TEST" ;
    private static final int n = 10;

    @Test
    public void createVariable() throws Exception {
        TVariable var = variable(name);
        assertEquals("Should create a variable with the correct name", name, var.name());
    }

    @Test
    public void createVariables() throws Exception {
        String[] names = new String[n];
        for (int i = 0; i < n; i++) names[i] = name + i;

// Path: src/main/java/inference/Substitution.java
// public class Substitution extends Substitutable<Substitution> {
//     private HashMap<TVariable, Type> subs = new HashMap<>();
// 
//     public Substitution() {}
// 
//     public Substitution(TVariable variable, Type type) {
//         subs.put(variable, type);
//     }
// 
//     private Substitution(Substitution previous) {
//         subs.putAll(previous.subs);
//     }
// 
//     public Substitution(List<TVariable> vars, List<Type> substitute) {
//         if(vars.size() != substitute.size())
//             throw new IllegalArgumentException("Number of variables have to match number of types");
// 
//         for (int i = 0; i < vars.size(); i++) subs.put(vars.get(i), substitute.get(i));
//     }
// 
//     public List<TVariable> variables() {
//         return new LinkedList<>(subs.keySet());
//     }
// 
//     public Type substituteOf(TVariable var) {
//         return subs.get(var);
//     }
// 
//     public Substitution composeWith(Substitution sub) {
//         Substitution substituted = new Substitution(sub);
//         substituted.apply(this);
//         subs.putAll(substituted.subs);
//         return this;
//     }
// 
//     @Override
//     public HashSet<TVariable> ftv() {
//         HashSet<TVariable> freeVars = new HashSet<>();
//         for (TVariable var : variables()) freeVars.addAll(substituteOf(var).ftv());
//         return freeVars;
//     }
// 
//     @Override
//     public Substitution substitute(TVariable var, Type t) {
//         for (TVariable variable : variables())
//             subs.replace(variable, substituteOf(variable).substitute(var, t));
//         return this;
//     }
// 
//     @Override
//     public String toString() {
//         return subs.toString();
//     }
// 
//     @Override
//     public Substitution identity() {
//         return this;
//     }
// }
// 
// Path: src/main/java/types/TVariable.java
// public static TVariable variable(String name) {
//     TVariable var = new TVariable(name);
//     if(!instantiated.add(var)) System.out.println("Creation avoidable : TVariable(" + name + ")");
//     return var;
// }
// 
// Path: src/main/java/types/TVariable.java
// public static List<TVariable> variables(String... names) {
//     List<TVariable> variables = new LinkedList<>();
//     for (String name : names) variables.add(new TVariable(name));
//     return variables;
// }


// Path: src/test/java/types/TVariableTest.java
import inference.Substitution;
import org.junit.Test;
import java.util.*;
import static org.junit.Assert.assertEquals;
import static types.TVariable.variable;
import static types.TVariable.variables;

package types;




/**
 * Created by valentin on 20/10/2016.
 */
public class TVariableTest {
    private static final String name = "TEST" ;
    private static final int n = 10;

    @Test
    public void createVariable() throws Exception {
        TVariable var = variable(name);
        assertEquals("Should create a variable with the correct name", name, var.name());
    }

    @Test
    public void createVariables() throws Exception {
        String[] names = new String[n];
        for (int i = 0; i < n; i++) names[i] = name + i;

        List<TVariable> vars = variables(names);