/*
 * Copyright 2012-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.facebook.buck.util;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;

import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class FakeProcessExecutor extends ProcessExecutor {

  private final ImmutableMap<ProcessExecutorParams, FakeProcess> processMap;
  private final Set<ProcessExecutorParams> launchedProcesses;

  public FakeProcessExecutor() {
    this(ImmutableMap.<ProcessExecutorParams, FakeProcess>of());
  }

  public FakeProcessExecutor(Map<ProcessExecutorParams, FakeProcess> processMap) {
    this(processMap, new Console(Verbosity.ALL, System.out, System.err, Ansi.withoutTty()));
  }

  public FakeProcessExecutor(
      Map<ProcessExecutorParams, FakeProcess> processMap,
      Console console) {
    super(console);
    this.processMap = ImmutableMap.copyOf(processMap);
    this.launchedProcesses = new HashSet<>();
  }

  @Override
  Process launchProcessInternal(ProcessExecutorParams params) throws IOException {
    Preconditions.checkArgument(processMap.keySet().contains(params), params.toString());
    FakeProcess fakeProcess = Preconditions.checkNotNull(processMap.get(params));
    launchedProcesses.add(params);
    return fakeProcess;
  }

  public boolean isProcessLaunched(ProcessExecutorParams params) {
    return launchedProcesses.contains(params);
  }
}

@@ -633,16 +633,97 @@
 .util;%0A%0A
+import com.google.common.base.Function;%0Aimport com.google.common.base.Functions;%0A
 import c
@@ -861,16 +861,43 @@
 ashSet;%0A
+import java.util.Iterator;%0A
 import j
@@ -1009,28 +1009,24 @@
 e final 
-ImmutableMap
+Function
 %3CProcess
@@ -1061,19 +1061,24 @@
  process
-Map
+Function
 ;%0A  priv
@@ -1454,19 +1454,34 @@
 (%0A      
-Map
+Iterable%3CMap.Entry
 %3CProcess
@@ -1508,24 +1508,25 @@
 Process%3E
+%3E
  process
 Map,%0A   
@@ -1521,56 +1521,260 @@
 cess
-Map,%0A      Console console) %7B%0A    super(
+Iterable) %7B%0A    this(processIterable, new Console(Verbosity.ALL, System.out, System.err, Ansi.withoutTty()));%0A  %7D%0A%0A  public FakeProcessExecutor(%0A      final Iterable%3CMap.Entry%3CProcessExecutorParams, FakeProcess%3E%3E processIterable,%0A      Console 
 console)
 ;%0A  
@@ -1769,17 +1769,18 @@
 console)
-;
+ %7B
 %0A    thi
@@ -1784,370 +1784,1445 @@
 this
-.processMap = ImmutableMap.copyOf(processMap);%0A    this.launchedProcesses = new HashSet%3C%3E();%0A  %7D%0A%0A  @Override%0A  Process launchProcessInternal(ProcessExecutorParams params) throws IOException %7B%0A    Preconditions.checkArgument(processMap.keySet().contains(p
+(%0A        new Function%3CProcessExecutorParams, FakeProcess%3E() %7B%0A          final Iterator%3CMap.Entry%3CProcessExecutorParams, FakeProcess%3E%3E processIterator =%0A              processIterable.iterator();%0A%0A          @Override%0A          public FakeProcess apply(ProcessExecutorParams params) %7B%0A            Preconditions.checkState(%0A                processIterator.hasNext(),%0A                %22Ran out of fake processes when asked to run %25s%22,%0A                params);%0A            Map.Entry%3CProcessExecutorParams, FakeProcess%3E nextProcess = processIterator.next();%0A            Preconditions.checkState(%0A                nextProcess.getKey().equals(params),%0A                %22Mismatch when asked to run process %25s (expecting %25s)%22,%0A                params,%0A                nextProcess.getKey());%0A            return nextProcess.getValue();%0A          %7D%0A        %7D,%0A        console);%0A  %7D%0A%0A  public FakeProcessExecutor(%0A      Map%3CProcessExecutorP
 arams
-)
 , 
-params.toString());%0A    FakeProcess fakeProcess = Preconditions.checkNotNull(processMap.get
+FakeProcess%3E processMap,%0A      Console console) %7B%0A    this(Functions.forMap(processMap), console);%0A  %7D%0A%0A  public FakeProcessExecutor(%0A      Function%3CProcessExecutorParams, FakeProcess%3E processFunction,%0A      Console console) %7B%0A    super(console);%0A    this.processFunction = processFunction;%0A    this.launchedProcesses = new HashSet%3C%3E();%0A  %7D%0A%0A  @Override%0A  Process launchProcessInternal(ProcessExecutorParams params) throws IOException %7B%0A    try %7B%0A      FakeProcess fakeProcess = processFunction.apply
 (params)
 );%0A 
@@ -3217,19 +3217,20 @@
 (params)
-)
 ;%0A
+  
     laun
@@ -3256,24 +3256,26 @@
 arams);%0A    
+  
 return fakeP
@@ -3282,16 +3282,225 @@
 rocess;%0A
+    %7D catch (IllegalArgumentException e) %7B%0A      throw new IOException(%0A          String.format(%0A              %22FakeProcessExecutor not configured to run process with params %25s%22,%0A              params));%0A    %7D%0A
   %7D%0A%0A  p

Allow FakeProcessExecutor to run a sequence of processes (even if they have the same params)