private static void duelFieldDataLong(
      Random random,
      AtomicReaderContext context,
      IndexNumericFieldData left,
      IndexNumericFieldData right)
      throws Exception {
    AtomicNumericFieldData leftData =
        random.nextBoolean() ? left.load(context) : left.loadDirect(context);
    AtomicNumericFieldData rightData =
        random.nextBoolean() ? right.load(context) : right.loadDirect(context);

    int numDocs = context.reader().maxDoc();
    SortedNumericDocValues leftLongValues = leftData.getLongValues();
    SortedNumericDocValues rightLongValues = rightData.getLongValues();
    for (int i = 0; i < numDocs; i++) {
      leftLongValues.setDocument(i);
      rightLongValues.setDocument(i);
      int numValues = leftLongValues.count();
      long previous = 0;
      assertThat(numValues, equalTo(rightLongValues.count()));
      for (int j = 0; j < numValues; j++) {
        long current;
        assertThat(leftLongValues.valueAt(j), equalTo(current = rightLongValues.valueAt(j)));
        if (j > 0) {
          assertThat(previous, lessThan(current));
        }
        previous = current;
      }
    }
  }
  private static void duelFieldDataDouble(
      Random random,
      AtomicReaderContext context,
      IndexNumericFieldData left,
      IndexNumericFieldData right)
      throws Exception {
    AtomicNumericFieldData leftData =
        random.nextBoolean() ? left.load(context) : left.loadDirect(context);
    AtomicNumericFieldData rightData =
        random.nextBoolean() ? right.load(context) : right.loadDirect(context);

    int numDocs = context.reader().maxDoc();
    SortedNumericDoubleValues leftDoubleValues = leftData.getDoubleValues();
    SortedNumericDoubleValues rightDoubleValues = rightData.getDoubleValues();
    for (int i = 0; i < numDocs; i++) {
      leftDoubleValues.setDocument(i);
      rightDoubleValues.setDocument(i);
      int numValues = leftDoubleValues.count();
      assertThat(numValues, equalTo(rightDoubleValues.count()));
      double previous = 0;
      for (int j = 0; j < numValues; j++) {
        double current = rightDoubleValues.valueAt(j);
        if (Double.isNaN(current)) {
          assertTrue(Double.isNaN(leftDoubleValues.valueAt(j)));
        } else {
          assertThat(leftDoubleValues.valueAt(j), closeTo(current, 0.0001));
        }
        if (j > 0) {
          assertThat(Double.compare(previous, current), lessThan(0));
        }
        previous = current;
      }
    }
  }
  @Test
  public void testDateScripts() throws Exception {
    fillSingleValueAllSet();
    IndexNumericFieldData indexFieldData = getForField("value");
    AtomicNumericFieldData fieldData = indexFieldData.load(refreshReader());

    ScriptDocValues.Longs scriptValues = (ScriptDocValues.Longs) fieldData.getScriptValues();
    scriptValues.setNextDocId(0);
    assertThat(scriptValues.getValue(), equalTo(2l));
    assertThat(scriptValues.getDate().getMillis(), equalTo(2l));
    assertThat(scriptValues.getDate().getZone(), equalTo(DateTimeZone.UTC));
  }
  private void test(List<TLongSet> values) throws Exception {
    StringField id = new StringField("_id", "", Field.Store.NO);

    for (int i = 0; i < values.size(); ++i) {
      Document doc = new Document();
      id.setStringValue("" + i);
      doc.add(id);
      final TLongSet v = values.get(i);
      for (TLongIterator it = v.iterator(); it.hasNext(); ) {
        LongField value = new LongField("value", it.next(), Field.Store.NO);
        doc.add(value);
      }
      writer.addDocument(doc);
    }
    writer.forceMerge(1);

    final IndexNumericFieldData indexFieldData = getForField("value");
    final AtomicNumericFieldData atomicFieldData = indexFieldData.load(refreshReader());
    final LongValues data = atomicFieldData.getLongValues();
    final DoubleValues doubleData = atomicFieldData.getDoubleValues();
    final TLongSet set = new TLongHashSet();
    final TDoubleSet doubleSet = new TDoubleHashSet();
    for (int i = 0; i < values.size(); ++i) {
      final TLongSet v = values.get(i);

      assertThat(data.hasValue(i), equalTo(!v.isEmpty()));
      assertThat(doubleData.hasValue(i), equalTo(!v.isEmpty()));

      if (v.isEmpty()) {
        assertThat(data.getValue(i), equalTo(0L));
        assertThat(doubleData.getValue(i), equalTo(0d));
      }

      set.clear();
      for (LongValues.Iter iter = data.getIter(i); iter.hasNext(); ) {
        set.add(iter.next());
      }
      assertThat(set, equalTo(v));

      final TDoubleSet doubleV = new TDoubleHashSet();
      for (TLongIterator it = v.iterator(); it.hasNext(); ) {
        doubleV.add((double) it.next());
      }
      doubleSet.clear();
      for (DoubleValues.Iter iter = doubleData.getIter(i); iter.hasNext(); ) {
        doubleSet.add(iter.next());
      }
      assertThat(doubleSet, equalTo(doubleV));
    }
  }
  @Test
  public void testOptimizeTypeLong() throws Exception {
    Document d = new Document();
    d.add(new StringField("_id", "1", Field.Store.NO));
    d.add(new LongField("value", Integer.MAX_VALUE + 1l, Field.Store.NO));
    writer.addDocument(d);

    d = new Document();
    d.add(new StringField("_id", "2", Field.Store.NO));
    d.add(new LongField("value", Integer.MIN_VALUE - 1l, Field.Store.NO));
    writer.addDocument(d);

    IndexNumericFieldData indexFieldData =
        ifdService.getForField(new FieldMapper.Names("value"), new FieldDataType("long"));
    AtomicNumericFieldData fieldData = indexFieldData.load(refreshReader());
    assertThat(fieldData, instanceOf(PackedArrayAtomicFieldData.class));
    assertThat(fieldData.getLongValues().getValue(0), equalTo((long) Integer.MAX_VALUE + 1l));
    assertThat(fieldData.getLongValues().getValue(1), equalTo((long) Integer.MIN_VALUE - 1l));
  }