@Test
  public void testGroupByWithSum1()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    Object[][] rows1 = {{0}, {2}, {2}, {5}, {10}, {100}};
    Block block = new ArrayBlock(Arrays.asList(rows1), new String[] {"a"}, 1);

    TupleOperator operator = new GroupByOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("first", block);

    ObjectMapper mapper = new ObjectMapper();
    ObjectNode json = mapper.createObjectNode();
    json.put("input", "first");
    ArrayNode anode = mapper.createArrayNode();
    anode.add("a");
    json.put("groupBy", anode);
    anode = mapper.createArrayNode();
    ObjectNode onode = mapper.createObjectNode();
    onode.put("type", "SUM");
    onode.put("input", "a");
    onode.put("output", "sum");
    anode.add(onode);
    json.put("aggregates", anode);

    BlockProperties props =
        new BlockProperties(null, new BlockSchema("INT a, INT sum"), (BlockProperties) null);
    operator.setInput(input, json, props);

    Block output = new TupleOperatorBlock(operator, props);

    ArrayBlock.assertData(
        output,
        new Object[][] {{0, 0}, {2, 4}, {5, 5}, {10, 10}, {100, 100}},
        new String[] {"a", "sum"});
  }
  @Test
  public void testSortOperator()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    System.out.println("Testing SORT operator");

    Object[][] rows1 = {{0, 10, 0}, {2, 5, 2}, {2, 8, 5}, {5, 9, 6}, {10, 11, 1}, {100, 6, 10}};
    Block block = new ArrayBlock(Arrays.asList(rows1), new String[] {"a", "b", "c"}, 1);

    TupleOperator operator = new SortOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("unsorted", block);

    ObjectMapper mapper = new ObjectMapper();

    ObjectNode json = mapper.createObjectNode();
    json.put("input", "unsorted");
    ArrayNode anode = mapper.createArrayNode();
    anode.add("b");
    anode.add("c");
    json.put("sortBy", anode);

    BlockProperties props =
        new BlockProperties(null, new BlockSchema("INT a, INT b, INT c"), (BlockProperties) null);
    operator.setInput(input, json, props);

    Block output = new TupleOperatorBlock(operator, props);

    System.out.println("output is " + output);
    ArrayBlock.assertData(
        output,
        new Object[][] {{2, 5, 2}, {100, 6, 10}, {2, 8, 5}, {5, 9, 6}, {0, 10, 0}, {10, 11, 1}},
        new String[] {"a", "b", "c"});
  }
  @Test
  // when there are multiple rows in one table
  public void testMergeJoin4()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    Object[][] rows1 = {{0}, {2}, {2}, {5}, {10}, {100}};
    Object[][] rows2 = {{1}, {2}, {7}, {9}, {100}, {100}};
    Object[][] expected = {{2, 2}, {2, 2}, {100, 100}, {100, 100}};

    Block block1 = new ArrayBlock(Arrays.asList(rows1), new String[] {"a"});
    Block block2 = new ArrayBlock(Arrays.asList(rows2), new String[] {"a"});

    TupleOperator operator = new MergeJoinOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("block1", block1);
    input.put("block2", block2);

    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    node.put("leftCubeColumns", "a");
    node.put("rightCubeColumns", "a");
    node.put("leftBlock", "block1");

    BlockProperties props =
        new BlockProperties(
            null, new BlockSchema("INT block1___a, INT block2___a"), (BlockProperties) null);
    operator.setInput(input, node, props);

    Block output = new TupleOperatorBlock(operator, props);

    ArrayBlock.assertData(output, expected, new String[] {"block1.a", "block2.a"});
  }
  public void testDictionaryEncoding() throws IOException, InterruptedException {
    // create dictionary block
    Object[][] dictRows = {{1000, 100, 1}, {1000, 101, 2}};
    Block dictionary =
        new ArrayBlock(Arrays.asList(dictRows), new String[] {"colname", "colvalue", "code"});

    // create data block
    Object[][] dataRows = {{100, 10}, {100, 11}, {101, 10}};
    Block dataBlock = new ArrayBlock(Arrays.asList(dataRows), new String[] {"1000", "a"});

    // create operator
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("block1", dictionary);
    input.put("block2", dataBlock);
    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    node.put("dictionary", "block1");

    TupleOperator operator = new DictionaryEncodeOperator();
    BlockProperties props =
        new BlockProperties(null, new BlockSchema("INT 1000, INT a"), (BlockProperties) null);
    operator.setInput(input, node, props);

    Block output = new TupleOperatorBlock(operator, props);

    Object[][] expected = {{1, 10}, {1, 11}, {2, 10}};

    ArrayBlock.assertData(output, expected, new String[] {"1000", "a"});
  }
  @Test
  public void testCombinedBlockLeftRunsout()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    Object[][] rows1 = {{2}, {7}, {9}};
    Object[][] rows2 = {{3}, {5}, {10}};

    Block block1 = new ArrayBlock(Arrays.asList(rows1), new String[] {"a"}, 1);
    Block block2 = new ArrayBlock(Arrays.asList(rows2), new String[] {"a"}, 1);

    TupleOperator operator = new CombineOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("cube1", block1);
    input.put("cube2", block2);

    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    JsonNode ct = mapper.readValue("[\"a\"]", JsonNode.class);
    node.put("pivotBy", ct);

    BlockProperties props =
        new BlockProperties(null, new BlockSchema("INT a"), (BlockProperties) null);
    operator.setInput(input, node, props);

    Block output = new TupleOperatorBlock(operator, props);

    ArrayBlock.assertData(
        output, new Object[][] {{2}, {3}, {5}, {7}, {9}, {10}}, new String[] {"a"});
  }
  @Test
  public void testMergeJoinFullOuterEmptyRight()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    Object[][] rows1 = {{0}, {2}, {2}, {5}, {10}, {100}};
    Object[][] rows2 = {};
    Object[][] expected = {{0, null}, {2, null}, {2, null}, {5, null}, {10, null}, {100, null}};

    Block block1 = new ArrayBlock(Arrays.asList(rows1), new String[] {"a"});
    Block block2 = new ArrayBlock(Arrays.asList(rows2), new String[] {"a"});

    TupleOperator operator = new MergeJoinOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("block1", block1);
    input.put("block2", block2);

    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    node.put("leftCubeColumns", "a");
    node.put("rightCubeColumns", "a");
    node.put("leftBlock", "block1");
    node.put("rightBlock", "block2");
    node.put("joinType", "full outer");
    BlockProperties props =
        new BlockProperties(
            null, new BlockSchema("INT block1___a, INT block2___a"), (BlockProperties) null);
    operator.setInput(input, node, props);

    Block output = new TupleOperatorBlock(operator, props);

    ArrayBlock.assertData(output, expected, new String[] {"block1.a", "block2.a"});
    System.out.println("Successfully tested MERGE JOIN FULL OUTER empty block");
  }
  @Test
  // testing multiple join keys
  public void testMergeJoinMultipleJoinKeys()
      throws JsonGenerationException, JsonMappingException, IOException, InterruptedException {
    Object[][] rows1 = {{0, 1}, {2, 1}, {2, 2}, {5, 1}, {10, 1}, {100, 1}};
    Object[][] rows2 = {{1, 1}, {2, 0}, {2, 1}, {5, 1}, {100, 2}, {100, 3}};
    Object[][] expected = {{2, 1, 2, 1}, {5, 1, 5, 1}};

    Block block1 = new ArrayBlock(Arrays.asList(rows1), new String[] {"a", "b"});
    Block block2 = new ArrayBlock(Arrays.asList(rows2), new String[] {"c", "a"});

    TupleOperator operator = new MergeJoinOperator();
    Map<String, Block> input = new HashMap<String, Block>();
    input.put("block1", block1);
    input.put("block2", block2);

    ObjectMapper mapper = new ObjectMapper();
    ObjectNode node = mapper.createObjectNode();
    ArrayNode lkeys = mapper.createArrayNode();
    lkeys.add("a");
    lkeys.add("b");
    node.put("leftCubeColumns", lkeys);
    ArrayNode rkeys = mapper.createArrayNode();
    rkeys.add("c");
    rkeys.add("a");
    node.put("rightCubeColumns", rkeys);
    node.put("leftBlock", "block1");

    BlockProperties props =
        new BlockProperties(
            null,
            new BlockSchema("INT block1___a, INT block1___b, INT block2___c, INT block2___a"),
            (BlockProperties) null);
    operator.setInput(input, node, props);

    Block output = new TupleOperatorBlock(operator, props);

    ArrayBlock.assertData(output, expected, new String[] {"block1.a", "block2.a"});
  }