content: package dk.alexandra.fresco.lib.fixed;
  
  import static org.junit.Assert.assertEquals;
  
  import dk.alexandra.fresco.framework.Application;
  import dk.alexandra.fresco.framework.DRes;
  import dk.alexandra.fresco.framework.TestThreadRunner.TestThread;
  import dk.alexandra.fresco.framework.TestThreadRunner.TestThreadFactory;
  import dk.alexandra.fresco.framework.builder.numeric.ProtocolBuilderNumeric;
  import dk.alexandra.fresco.framework.sce.resources.ResourcePool;
  import dk.alexandra.fresco.framework.value.SInt;
  import java.math.BigDecimal;
  import java.math.BigInteger;
  import java.math.RoundingMode;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.stream.Collectors;
  import java.util.stream.IntStream;
  import java.util.stream.Stream;
  import org.junit.Assert;
  
  /**
   * Basic tests of computation with fixed point numbers.
   * <p>
   * NOTE: these tests all assume a precision of {@link BasicFixedPointTests#DEFAULT_PRECISION}.
   * </p>
   */
  public class BasicFixedPointTests {
  
    /**
     * The precision assumed in all tests.
     */
    public static final int DEFAULT_PRECISION = 16;
  
    public static class TestInput<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
        List<BigDecimal> value = Stream
            .of(10.000001, 5.9, 11.0, 0.0001, 100000000.0001, 1.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> inputs = value.stream().map(
                  x -> fixedNumeric.input(producer.getBasicNumericContext().getMyId() == 1 ? x : null,
                      1))
                  .collect(Collectors.toList());
              List<DRes<BigDecimal>> opened =
                  inputs.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
            FixedTestUtils.assertEqual(value, output, DEFAULT_PRECISION + 1);
          }
        };
      }
    }
  
    public static class TestUseSInt<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<BigInteger> value = Arrays.asList(BigInteger.ONE, BigInteger.ONE.negate(),
            BigInteger.ONE.shiftLeft(200).negate());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SInt>> sints =
                  value.stream().map(producer.numeric()::known).collect(Collectors.toList());
              List<DRes<SFixed>> inputs =
                  sints.stream().map(fixedNumeric::fromSInt).collect(Collectors.toList());
              List<DRes<BigDecimal>> opened =
                  inputs.stream().map(fixedNumeric::open).collect(Collectors.toList());
  
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
            FixedTestUtils.assertEqual(
                value.stream().map(BigDecimal::new).collect(Collectors.toList()), output,
                DEFAULT_PRECISION + 1);
          }
        };
      }
    }
  
    public static class TestOpenToParty<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        BigDecimal value = BigDecimal.ONE;
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<BigDecimal, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              DRes<SFixed> input = fixedNumeric.input(value, 1);
              return fixedNumeric.open(input, 1);
            };
            BigDecimal output = runApplication(app);
  
            if (conf.getMyId() == 1) {
              FixedTestUtils.assertEqual(value, output, DEFAULT_PRECISION + 1);
            } else {
              Assert.assertNull(output);
            }
          }
        };
      }
    }
  
    public static class TestKnown<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<Double> value = Stream
            .of(10.000001, 5.9, 11.0, 0.0001, 100000000.0001, 0.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> inputs =
                  value.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<BigDecimal>> opened =
                  inputs.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
  
            for (int i = 0; i < output.size(); i++) {
              FixedTestUtils.assertEqual(value.get(i), output.get(i), DEFAULT_PRECISION + 1);
            }
          }
        };
      }
    }
  
    public static class TestAddKnown<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<Double> openInputs =
            Stream.of(1.0001, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1,
                0.5 * Math.pow(2.0, -DEFAULT_PRECISION)).collect(Collectors.toList());
        List<Double> openInputs2 =
            Stream.of(-1.0001, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1,
                0.5 * Math.pow(2.0, -DEFAULT_PRECISION)).collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
  
              List<DRes<SFixed>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(
                    fixedNumeric.add(openInputs2.get(closed1.indexOf(inputX)), inputX));
              }
  
              List<DRes<BigDecimal>> opened =
                  result.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
  
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
  
              double a = openInputs.get(idx);
              double b = openInputs2.get(idx);
              FixedTestUtils.assertEqual(BigDecimal.valueOf(a + b), openOutput, DEFAULT_PRECISION);
            }
          }
        };
      }
    }
  
    public static class TestSubtractSecret<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<BigDecimal> openInputs = Stream
            .of(1.000_2, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1,
                2.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        List<BigDecimal> openInputs2 = Stream
            .of(1.000_1, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1,
                Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<SFixed>> closed2 = openInputs2.stream().map(fixedNumeric::known)
                  .collect(Collectors.toList());
  
              List<DRes<SFixed>> results = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                results.add(fixedNumeric.sub(inputX, closed2.get(closed1.indexOf(inputX))));
              }
  
              List<DRes<BigDecimal>> opened =
                  results.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
  
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
  
              BigDecimal a = openInputs.get(idx);
              BigDecimal b = openInputs2.get(idx);
              FixedTestUtils.assertEqual(a.subtract(b), openOutput, DEFAULT_PRECISION);
            }
          }
        };
      }
    }
  
    public static class TestSubKnown<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<Double> openInputs = Stream
            .of(1.000_2, 0.000_000_001, -1_000_000_000_000.000_100_000_000_1,
                2.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .collect(Collectors.toList());
        List<Double> openInputs2 = Stream
            .of(1.000_1, 1_000_000_000.0, -1_000_000_000_000.000_100_000_000_1,
                Math.pow(2.0, -DEFAULT_PRECISION))
            .collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<BigDecimal>> opened = Stream
                  .concat(
                      IntStream.range(0, closed.size()).mapToObj(
                          i -> fixedNumeric.sub(closed.get(i), openInputs2.get(i))),
                      IntStream.range(0, closed.size()).mapToObj(
                          i -> fixedNumeric.sub(openInputs2.get(i), closed.get(i))))
                  .map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
            assertEquals(output.size(), openInputs.size() * 2);
            IntStream.range(0, openInputs.size()).forEach(idx -> {
              double a = openInputs.get(idx);
              double b = openInputs2.get(idx);
              FixedTestUtils.assertEqual(a-b, output.get(idx), DEFAULT_PRECISION);
            });
  
            IntStream.range(openInputs.size(), output.size()).forEach(idx -> {
              double a = openInputs.get(idx - openInputs.size());
              double b = openInputs2.get(idx - openInputs.size());
              FixedTestUtils.assertEqual(b-a, output.get(idx), DEFAULT_PRECISION);
            });
          }
        };
      }
    }
  
    public static class TestMultKnown<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
        List<Double> openInputs =
            Arrays.asList(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.007, 0.1298, 9.99);
        List<Double> openInputs2 =
            Arrays.asList(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.005, 10.0012, 999.0101);
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
  
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
  
              List<DRes<SFixed>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(
                    fixedNumeric.mult(openInputs2.get(closed1.indexOf(inputX)), inputX));
              }
  
              List<DRes<BigDecimal>> opened =
                  result.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
              double a = openInputs.get(idx);
              double b = openInputs2.get(idx);
              // There should be no truncation after just one multiplication
              int precision = DEFAULT_PRECISION
                  - Math.max(0, Math.max(FixedTestUtils.floorLog2(a), FixedTestUtils.floorLog2(b)));
              FixedTestUtils.assertEqual(a*b, openOutput, precision);
            }
          }
        };
      }
    }
  
    public static class TestRepeatedMultiplication<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
        List<BigDecimal> openInputs =
            Stream.of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.1298)
                .map(BigDecimal::valueOf).collect(Collectors.toList());
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<BigDecimal, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
  
              DRes<SFixed> result = fixedNumeric.known(BigDecimal.ONE);
              for (DRes<SFixed> inputX : closed1) {
                result = fixedNumeric.mult(result, inputX);
              }
  
              DRes<BigDecimal> opened = fixedNumeric.open(result);
              return opened;
            };
            BigDecimal output = runApplication(app);
  
            BigDecimal expected = BigDecimal.ONE.setScale(DEFAULT_PRECISION / 2);
            for (BigDecimal openOutput : openInputs) {
              expected = expected.multiply(openOutput);
            }
            // We lose precision for each multiplication.
            FixedTestUtils.assertEqual(output, expected, DEFAULT_PRECISION - 8);
          }
        };
      }
    }
  
    public static class TestDivisionKnownDivisor<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        double value = 10.00100;
        double value2 = 0.2;
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<BigDecimal, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
  
              DRes<SFixed> input = fixedNumeric.input(value, 1);
              DRes<SFixed> product = fixedNumeric.div(input, value2);
  
              return fixedNumeric.open(product);
            };
            BigDecimal output = runApplication(app);
            int precision = DEFAULT_PRECISION - 2
                - Math.max(0, FixedTestUtils.floorLog2(value) - FixedTestUtils.floorLog2(value2));
            FixedTestUtils.assertEqual(value / value2, output, precision);
          }
        };
      }
    }
  
    public static class TestDivisionKnownNegativeDivisor<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        double value = 10.00100;
        double value2 = -1;
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<BigDecimal, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
  
              DRes<SFixed> input = fixedNumeric.input(value, 1);
              DRes<SFixed> product = fixedNumeric.div(input, value2);
  
              return fixedNumeric.open(product);
            };
            BigDecimal output = runApplication(app);
            int precision = DEFAULT_PRECISION - 2
                - Math.max(0, FixedTestUtils.floorLog2(value) - FixedTestUtils.floorLog2(value2));
            FixedTestUtils.assertEqual(value / value2, output, precision);
          }
        };
      }
    }
  
    public static class TestMult<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
        List<BigDecimal> openInputs = Stream
            .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.007, 0.1298,
                1.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        List<BigDecimal> openInputs2 = Stream
            .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.005, 10.0012,
                3.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<SFixed>> closed2 = openInputs2.stream().map(fixedNumeric::known)
                  .collect(Collectors.toList());
  
              List<DRes<SFixed>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(fixedNumeric.mult(inputX, closed2.get(closed1.indexOf(inputX))));
              }
  
              List<DRes<BigDecimal>> opened =
                  result.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
  
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
  
              BigDecimal a = openInputs.get(idx);
              BigDecimal b = openInputs2.get(idx);
  
              int precision = DEFAULT_PRECISION - 1
                  - Math.max(0, Math.max(FixedTestUtils.floorLog2(a), FixedTestUtils.floorLog2(b)));
              FixedTestUtils.assertEqual(a.multiply(b), openOutput, precision);
            }
          }
        };
      }
    }
  
    public static class TestAdd<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<BigDecimal> openInputs = Stream
            .of(1.223, 222.23, 5.59703, 0.004, 5.90, 6.0, 0.0007, 0.121998,
                0.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        List<BigDecimal> openInputs2 = Stream
            .of(1.000, 1.0000, 0.22211, 100.1, 11.0, .07, 0.0005, 10.00112,
                0.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<SFixed>> closed2 = openInputs2.stream().map(fixedNumeric::known)
                  .collect(Collectors.toList());
  
              List<DRes<SFixed>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(fixedNumeric.add(inputX, closed2.get(closed1.indexOf(inputX))));
              }
  
              List<DRes<BigDecimal>> opened =
                  result.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
  
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
  
              BigDecimal a = openInputs.get(idx);
              BigDecimal b = openInputs2.get(idx);
              FixedTestUtils.assertEqual(a.add(b), openOutput, DEFAULT_PRECISION);
            }
          }
        };
      }
    }
  
    public static class TestDiv<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
  
        List<BigDecimal> openInputs = Stream
            .of(2.0, Math.pow(2.0, DEFAULT_PRECISION - 1), -4.0,
                2.5 * Math.pow(2.0, -DEFAULT_PRECISION))
            .map(BigDecimal::valueOf).collect(Collectors.toList());
        List<BigDecimal> openInputs2 =
            Stream.of(-1.0, 2.2, -2.1, 2.0).map(BigDecimal::valueOf).collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigDecimal>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<SFixed>> closed2 = openInputs2.stream().map(fixedNumeric::known)
                  .collect(Collectors.toList());
              List<DRes<SFixed>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(fixedNumeric.div(inputX, closed2.get(closed1.indexOf(inputX))));
              }
              List<DRes<BigDecimal>> opened =
                  result.stream().map(fixedNumeric::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigDecimal> output = runApplication(app);
            for (BigDecimal openOutput : output) {
              int idx = output.indexOf(openOutput);
              BigDecimal a = openInputs.get(idx).setScale(DEFAULT_PRECISION, RoundingMode.HALF_UP);
              BigDecimal b = openInputs2.get(idx).setScale(DEFAULT_PRECISION, RoundingMode.HALF_UP);
              BigDecimal expected = a.divide(b, RoundingMode.HALF_UP);
              // It's hard to approximate error after division since it depends on the input sizes. We
              // use 4 for now.
              FixedTestUtils.assertEqual(expected, openOutput, 4);
            }
          }
        };
      }
    }
  
    public static class TestLeq<ResourcePoolT extends ResourcePool>
        extends TestThreadFactory<ResourcePoolT, ProtocolBuilderNumeric> {
  
      @Override
      public TestThread<ResourcePoolT, ProtocolBuilderNumeric> next() {
        List<BigDecimal> openInputs = Stream.of(1.1 * Math.pow(2.0, -DEFAULT_PRECISION + 1),
            Math.pow(2.0, DEFAULT_PRECISION - 1), -1.0).map(BigDecimal::valueOf)
            .collect(Collectors.toList());
        List<BigDecimal> openInputs2 = Stream
            .of(1.2 * Math.pow(2.0, -DEFAULT_PRECISION + 1),
                Math.pow(2.0, DEFAULT_PRECISION - 1) - 1.0, 1.0)
            .map(BigDecimal::valueOf).collect(Collectors.toList());
  
        return new TestThread<ResourcePoolT, ProtocolBuilderNumeric>() {
          @Override
          public void test() {
            Application<List<BigInteger>, ProtocolBuilderNumeric> app = producer -> {
              FixedNumeric fixedNumeric = FixedNumeric.using(producer);
  
              List<DRes<SFixed>> closed1 =
                  openInputs.stream().map(fixedNumeric::known).collect(Collectors.toList());
              List<DRes<SFixed>> closed2 = openInputs2.stream().map(fixedNumeric::known)
                  .collect(Collectors.toList());
  
              List<DRes<SInt>> result = new ArrayList<>();
              for (DRes<SFixed> inputX : closed1) {
                result.add(fixedNumeric.leq(inputX, closed2.get(closed1.indexOf(inputX))));
              }
  
              List<DRes<BigInteger>> opened =
                  result.stream().map(producer.numeric()::open).collect(Collectors.toList());
              return () -> opened.stream().map(DRes::out).collect(Collectors.toList());
            };
            List<BigInteger> output = runApplication(app);
  
            for (int i = 0; i < output.size(); i++) {
              BigDecimal a = openInputs.get(i);
              BigDecimal b = openInputs2.get(i);
              int expected = (a.compareTo(b) != 1) ? 1 : 0;
              int result = output.get(i).intValue();
              Assert.assertEquals(expected, result);
            }
          }
        };
      }
    }
  }
  