mirror of
https://github.com/jetty/jetty.project.git
synced 2025-02-15 11:04:49 +00:00
near 100% test coverage of NBitInteger, Huffman and HpackContext
This commit is contained in:
parent
58ed30e710
commit
ae4dea3e1e
@ -20,10 +20,11 @@ package org.eclipse.jetty.hpack;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.hpack.Field.NameKey;
|
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.util.ArrayQueue;
|
import org.eclipse.jetty.util.ArrayQueue;
|
||||||
import org.eclipse.jetty.util.ArrayTrie;
|
import org.eclipse.jetty.util.ArrayTrie;
|
||||||
@ -108,8 +109,7 @@ public class HpackContext
|
|||||||
Set<String> added = new HashSet<>();
|
Set<String> added = new HashSet<>();
|
||||||
for (int i=1;i<STATIC_TABLE.length;i++)
|
for (int i=1;i<STATIC_TABLE.length;i++)
|
||||||
{
|
{
|
||||||
Entry entry=new Entry(i,STATIC_TABLE[i][0],STATIC_TABLE[i][1],true);
|
Entry entry=__staticTable[i]=new Entry(i,STATIC_TABLE[i][0],STATIC_TABLE[i][1],true);
|
||||||
__staticTable[i]=entry;
|
|
||||||
if (entry._field.getValue()!=null)
|
if (entry._field.getValue()!=null)
|
||||||
__staticFieldMap.put(entry._field,entry);
|
__staticFieldMap.put(entry._field,entry);
|
||||||
if (!added.contains(entry._field.getName()))
|
if (!added.contains(entry._field.getName()))
|
||||||
@ -120,33 +120,46 @@ public class HpackContext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _maxHeaderTableSize;
|
private int _maxHeaderTableSizeInBytes;
|
||||||
private int _headerTableSize;
|
private int _headerTableSizeInBytes;
|
||||||
private final Entry _refSet=new Entry(true);
|
private final Entry _refSet=new Entry(true);
|
||||||
private final ArrayQueue<Entry> _headerTable;
|
private final HeaderTable _headerTable;
|
||||||
private final Map<HttpField,Entry> _fieldMap = new HashMap<>();
|
private final Map<HttpField,Entry> _fieldMap = new HashMap<>();
|
||||||
private final Map<String,Entry> _nameMap = new HashMap<>();
|
private final Map<String,Entry> _nameMap = new HashMap<>();
|
||||||
|
private Iterable<Entry> referenceSet = new Iterable<Entry>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
return iterateReferenceSet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
HpackContext(int maxHeaderTableSize)
|
HpackContext(int maxHeaderTableSize)
|
||||||
{
|
{
|
||||||
_maxHeaderTableSize=maxHeaderTableSize;
|
_maxHeaderTableSizeInBytes=maxHeaderTableSize;
|
||||||
int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10);
|
int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10);
|
||||||
_headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10);
|
_headerTable=new HeaderTable(guesstimateEntries,guesstimateEntries+10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resize(int maxHeaderTableSize)
|
||||||
|
{
|
||||||
|
_maxHeaderTableSizeInBytes=maxHeaderTableSize;
|
||||||
|
int guesstimateEntries = 10+maxHeaderTableSize/(32+10+10);
|
||||||
|
evict();
|
||||||
|
_headerTable.resizeUnsafe(guesstimateEntries);
|
||||||
|
}
|
||||||
|
|
||||||
public Entry get(HttpField field)
|
public Entry get(HttpField field)
|
||||||
{
|
{
|
||||||
System.err.println(field);
|
|
||||||
System.err.println(_fieldMap);
|
|
||||||
System.err.println(__staticFieldMap);
|
|
||||||
Entry entry = _fieldMap.get(field);
|
Entry entry = _fieldMap.get(field);
|
||||||
if (entry==null)
|
if (entry==null)
|
||||||
entry=__staticFieldMap.get(field);
|
entry=__staticFieldMap.get(field);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entry getNameEntry(String name)
|
public Entry get(String name)
|
||||||
{
|
{
|
||||||
Entry entry = __staticNameMap.get(name);
|
Entry entry = __staticNameMap.get(name);
|
||||||
if (entry!=null)
|
if (entry!=null)
|
||||||
@ -154,14 +167,27 @@ public class HpackContext
|
|||||||
return _nameMap.get(StringUtil.asciiToLowerCase(name));
|
return _nameMap.get(StringUtil.asciiToLowerCase(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Entry get(int index)
|
||||||
|
{
|
||||||
|
index=index-_headerTable.size();
|
||||||
|
if (index>0)
|
||||||
|
{
|
||||||
|
if (index>=__staticTable.length)
|
||||||
|
return null;
|
||||||
|
return __staticTable[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return _headerTable.getUnsafe(-index);
|
||||||
|
}
|
||||||
|
|
||||||
public Entry add(HttpField field)
|
public Entry add(HttpField field)
|
||||||
{
|
{
|
||||||
int i=_headerTable.getNextIndexUnsafe();
|
int i=_headerTable.getNextIndexUnsafe();
|
||||||
Entry entry=new Entry(i,field,false);
|
Entry entry=new Entry(i,field,false);
|
||||||
int size = entry.getSize();
|
int size = entry.getSize();
|
||||||
if (size>_maxHeaderTableSize)
|
if (size>_maxHeaderTableSizeInBytes)
|
||||||
return null;
|
return null;
|
||||||
_headerTableSize+=size;
|
_headerTableSizeInBytes+=size;
|
||||||
_headerTable.addUnsafe(entry);
|
_headerTable.addUnsafe(entry);
|
||||||
_fieldMap.put(field,entry);
|
_fieldMap.put(field,entry);
|
||||||
_nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry);
|
_nameMap.put(StringUtil.asciiToLowerCase(field.getName()),entry);
|
||||||
@ -169,14 +195,72 @@ public class HpackContext
|
|||||||
evict();
|
evict();
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void evict()
|
public Object size()
|
||||||
{
|
{
|
||||||
while (_headerTableSize>_maxHeaderTableSize)
|
return _headerTable.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int index(Entry entry)
|
||||||
|
{
|
||||||
|
if (entry._index<0)
|
||||||
|
return 0;
|
||||||
|
if (entry.isStatic())
|
||||||
|
return _headerTable.size() + entry._index;
|
||||||
|
return _headerTable.index(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToRefSet(Entry entry)
|
||||||
|
{
|
||||||
|
entry.addToRefSet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<Entry> getReferenceSet()
|
||||||
|
{
|
||||||
|
return referenceSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry> iterateReferenceSet()
|
||||||
|
{
|
||||||
|
return new Iterator<Entry>()
|
||||||
|
{
|
||||||
|
Entry _next = _refSet._refSetNext;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext()
|
||||||
|
{
|
||||||
|
return _next!=_refSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entry next()
|
||||||
|
{
|
||||||
|
if (_next==_refSet)
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
Entry next=_next;
|
||||||
|
_next=_next._refSetNext;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove()
|
||||||
|
{
|
||||||
|
if (_next._refSetPrev==_refSet)
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
|
||||||
|
_next._refSetPrev.removeFromRefSet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evict()
|
||||||
|
{
|
||||||
|
while (_headerTableSizeInBytes>_maxHeaderTableSizeInBytes)
|
||||||
{
|
{
|
||||||
Entry entry = _headerTable.pollUnsafe();
|
Entry entry = _headerTable.pollUnsafe();
|
||||||
_headerTableSize-=entry.getSize();
|
_headerTableSizeInBytes-=entry.getSize();
|
||||||
entry.removeFromRefSet();
|
entry.removeFromRefSet();
|
||||||
|
entry._index=-1;
|
||||||
_fieldMap.remove(entry.getHttpField());
|
_fieldMap.remove(entry.getHttpField());
|
||||||
String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName());
|
String lc=StringUtil.asciiToLowerCase(entry.getHttpField().getName());
|
||||||
if (entry==_nameMap.get(lc))
|
if (entry==_nameMap.get(lc))
|
||||||
@ -207,10 +291,10 @@ public class HpackContext
|
|||||||
* @see org.eclipse.jetty.util.ArrayQueue#growUnsafe()
|
* @see org.eclipse.jetty.util.ArrayQueue#growUnsafe()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void growUnsafe(int newCapacity)
|
protected void resizeUnsafe(int newCapacity)
|
||||||
{
|
{
|
||||||
// Relay on super.growUnsafe to pack all entries 0 to _nextSlot
|
// Relay on super.growUnsafe to pack all entries 0 to _nextSlot
|
||||||
super.growUnsafe(newCapacity);
|
super.resizeUnsafe(newCapacity);
|
||||||
for (int i=0;i<_nextSlot;i++)
|
for (int i=0;i<_nextSlot;i++)
|
||||||
((Entry)_elements[i])._index=i;
|
((Entry)_elements[i])._index=i;
|
||||||
}
|
}
|
||||||
@ -234,6 +318,17 @@ public class HpackContext
|
|||||||
{
|
{
|
||||||
return super.dequeue();
|
return super.dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* @param entry
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private int index(Entry entry)
|
||||||
|
{
|
||||||
|
return entry._index>=_nextE?_size-entry._index+_nextE:_nextSlot-entry._index;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -271,8 +366,15 @@ public class HpackContext
|
|||||||
_field=field;
|
_field=field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToRefSet(HpackContext ctx)
|
private void addToRefSet(HpackContext ctx)
|
||||||
{
|
{
|
||||||
|
if (_static)
|
||||||
|
throw new IllegalStateException("static");
|
||||||
|
if (_index<0)
|
||||||
|
throw new IllegalStateException("evicted");
|
||||||
|
if (_refSetNext!=this)
|
||||||
|
return;
|
||||||
|
|
||||||
_refSetNext=ctx._refSet;
|
_refSetNext=ctx._refSet;
|
||||||
_refSetPrev=ctx._refSet._refSetPrev;
|
_refSetPrev=ctx._refSet._refSetPrev;
|
||||||
ctx._refSet._refSetPrev._refSetNext=this;
|
ctx._refSet._refSetPrev._refSetNext=this;
|
||||||
@ -316,9 +418,7 @@ public class HpackContext
|
|||||||
return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode());
|
return String.format("{%s,%d,%s,%x}",_static?"S":"D",_index,_field,hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -316,8 +316,6 @@ public class Huffman
|
|||||||
{
|
{
|
||||||
len -= 8;
|
len -= 8;
|
||||||
int i = ((code >>> len) & 0xFF);
|
int i = ((code >>> len) & 0xFF);
|
||||||
if (rowbits[current]!=0)
|
|
||||||
throw new IllegalStateException("invalid dictionary: prefix not unique");
|
|
||||||
|
|
||||||
int t=current*256+i;
|
int t=current*256+i;
|
||||||
current = tree[t];
|
current = tree[t];
|
||||||
@ -404,7 +402,7 @@ public class Huffman
|
|||||||
for (int i=0;i<len;i++)
|
for (int i=0;i<len;i++)
|
||||||
{
|
{
|
||||||
char c=s.charAt(i);
|
char c=s.charAt(i);
|
||||||
if (c>=128)
|
if (c>=128 || c<' ')
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
needed += CODES[c][1];
|
needed += CODES[c][1];
|
||||||
}
|
}
|
||||||
@ -424,7 +422,7 @@ public class Huffman
|
|||||||
for (int i=0;i<len;i++)
|
for (int i=0;i<len;i++)
|
||||||
{
|
{
|
||||||
char c=s.charAt(i);
|
char c=s.charAt(i);
|
||||||
if (c>=128)
|
if (c>=128 || c<' ')
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
int code = CODES[c][0];
|
int code = CODES[c][0];
|
||||||
int bits = CODES[c][1];
|
int bits = CODES[c][1];
|
||||||
|
@ -24,12 +24,25 @@ public class NBitInteger
|
|||||||
{
|
{
|
||||||
public static int octectsNeeded(int n,int i)
|
public static int octectsNeeded(int n,int i)
|
||||||
{
|
{
|
||||||
|
if (n==8)
|
||||||
|
{
|
||||||
|
int nbits = 0xFF;
|
||||||
|
i=i-nbits;
|
||||||
|
if (i<0)
|
||||||
|
return 1;
|
||||||
|
if (i==0)
|
||||||
|
return 2;
|
||||||
|
int lz=Integer.numberOfLeadingZeros(i);
|
||||||
|
int log=32-lz;
|
||||||
|
return 1+(log+6)/7;
|
||||||
|
}
|
||||||
|
|
||||||
int nbits = 0xFF >>> (8 - n);
|
int nbits = 0xFF >>> (8 - n);
|
||||||
i=i-nbits;
|
i=i-nbits;
|
||||||
if (i<0)
|
if (i<0)
|
||||||
return n==8?1:0;
|
return 0;
|
||||||
if (i==0)
|
if (i==0)
|
||||||
return n==8?2:1;
|
return 1;
|
||||||
int lz=Integer.numberOfLeadingZeros(i);
|
int lz=Integer.numberOfLeadingZeros(i);
|
||||||
int log=32-lz;
|
int log=32-lz;
|
||||||
return (log+6)/7;
|
return (log+6)/7;
|
||||||
@ -96,9 +109,30 @@ public class NBitInteger
|
|||||||
|
|
||||||
public static int decode(ByteBuffer buf, int n)
|
public static int decode(ByteBuffer buf, int n)
|
||||||
{
|
{
|
||||||
|
if (n==8)
|
||||||
|
{
|
||||||
|
int nbits = 0xFF;
|
||||||
|
|
||||||
|
int i=buf.get()&0xff;
|
||||||
|
|
||||||
|
if (i == nbits)
|
||||||
|
{
|
||||||
|
int m=1;
|
||||||
|
int b;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
b = 0xff&buf.get();
|
||||||
|
i = i + (b&127) * m;
|
||||||
|
m = m*128;
|
||||||
|
}
|
||||||
|
while ((b&128) == 128);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
int nbits = 0xFF >>> (8 - n);
|
int nbits = 0xFF >>> (8 - n);
|
||||||
|
|
||||||
int i=buf.get(buf.position()-(n==8?0:1))&nbits;
|
int i=buf.get(buf.position()-1)&nbits;
|
||||||
|
|
||||||
if (i == nbits)
|
if (i == nbits)
|
||||||
{
|
{
|
||||||
|
@ -24,9 +24,15 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
import org.eclipse.jetty.hpack.HpackContext.Entry;
|
import org.eclipse.jetty.hpack.HpackContext.Entry;
|
||||||
import org.eclipse.jetty.http.HttpField;
|
import org.eclipse.jetty.http.HttpField;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -41,9 +47,10 @@ public class HpackContextTest
|
|||||||
public void testStaticName()
|
public void testStaticName()
|
||||||
{
|
{
|
||||||
HpackContext ctx = new HpackContext(4096);
|
HpackContext ctx = new HpackContext(4096);
|
||||||
Entry entry=ctx.getNameEntry(":method");
|
Entry entry=ctx.get(":method");
|
||||||
assertEquals(":method",entry.getHttpField().getName());
|
assertEquals(":method",entry.getHttpField().getName());
|
||||||
Assert.assertTrue(entry.isStatic());
|
Assert.assertTrue(entry.isStatic());
|
||||||
|
Assert.assertThat(entry.toString(),Matchers.startsWith("{S,2,:method: "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -67,7 +74,9 @@ public class HpackContextTest
|
|||||||
{
|
{
|
||||||
HpackContext ctx = new HpackContext(38);
|
HpackContext ctx = new HpackContext(38);
|
||||||
HttpField field = new HttpField("foo","bar");
|
HttpField field = new HttpField("foo","bar");
|
||||||
Assert.assertNotNull(ctx.add(field));
|
Entry entry=ctx.add(field);
|
||||||
|
Assert.assertNotNull(entry);
|
||||||
|
Assert.assertThat(entry.toString(),Matchers.startsWith("{D,0,foo: bar,"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -77,18 +86,53 @@ public class HpackContextTest
|
|||||||
HttpField field0 = new HttpField("foo","bar");
|
HttpField field0 = new HttpField("foo","bar");
|
||||||
|
|
||||||
assertEquals(field0,ctx.add(field0).getHttpField());
|
assertEquals(field0,ctx.add(field0).getHttpField());
|
||||||
assertEquals(field0,ctx.getNameEntry("foo").getHttpField());
|
assertEquals(field0,ctx.get("foo").getHttpField());
|
||||||
|
|
||||||
HttpField field1 = new HttpField("xxx","yyy");
|
HttpField field1 = new HttpField("xxx","yyy");
|
||||||
assertEquals(field1,ctx.add(field1).getHttpField());
|
assertEquals(field1,ctx.add(field1).getHttpField());
|
||||||
|
|
||||||
assertNull(ctx.get(field0));
|
assertNull(ctx.get(field0));
|
||||||
assertNull(ctx.getNameEntry("foo"));
|
assertNull(ctx.get("foo"));
|
||||||
assertEquals(field1,ctx.get(field1).getHttpField());
|
assertEquals(field1,ctx.get(field1).getHttpField());
|
||||||
assertEquals(field1,ctx.getNameEntry("xxx").getHttpField());
|
assertEquals(field1,ctx.get("xxx").getHttpField());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvictNames()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(38*2);
|
||||||
|
HttpField[] field =
|
||||||
|
{
|
||||||
|
new HttpField("name","v0"),
|
||||||
|
new HttpField("name","v1"),
|
||||||
|
new HttpField("name","v2"),
|
||||||
|
new HttpField("name","v3"),
|
||||||
|
new HttpField("name","v4"),
|
||||||
|
new HttpField("name","v5"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry[] entry = new Entry[field.length];
|
||||||
|
|
||||||
|
// Add 2 name entries to fill table
|
||||||
|
for (int i=0;i<=1;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
// check there is a name reference and it is the most recent added
|
||||||
|
assertEquals(entry[1],ctx.get("name"));
|
||||||
|
|
||||||
|
// Add 1 other entry to table and evict 1
|
||||||
|
ctx.add(new HttpField("xxx","yyy"));
|
||||||
|
|
||||||
|
// check the name reference has been not been evicted
|
||||||
|
assertEquals(entry[1],ctx.get("name"));
|
||||||
|
|
||||||
|
// Add 1 other entry to table and evict 1
|
||||||
|
ctx.add(new HttpField("foo","bar"));
|
||||||
|
|
||||||
|
// name is evicted
|
||||||
|
assertNull(ctx.get("name"));
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testGetAddStatic()
|
public void testGetAddStatic()
|
||||||
{
|
{
|
||||||
@ -116,5 +160,446 @@ public class HpackContextTest
|
|||||||
assertFalse(ctx.get(methodGet).isStatic());
|
assertFalse(ctx.get(methodGet).isStatic());
|
||||||
assertFalse(e0==e1);
|
assertFalse(e0==e1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAddStaticName()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(4096);
|
||||||
|
HttpField methodOther = new HttpField(":method","OTHER");
|
||||||
|
|
||||||
|
// Look for the field by name. Should find static version.
|
||||||
|
assertEquals(":method",ctx.get(":method").getHttpField().getName());
|
||||||
|
assertTrue(ctx.get(":method").isStatic());
|
||||||
|
|
||||||
|
// Add dynamic entry with method
|
||||||
|
ctx.add(methodOther);
|
||||||
|
|
||||||
|
// Look for the field by name. Should find static version.
|
||||||
|
assertEquals(":method",ctx.get(":method").getHttpField().getName());
|
||||||
|
assertTrue(ctx.get(":method").isStatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIndexes()
|
||||||
|
{
|
||||||
|
// Only enough space for 5 entries
|
||||||
|
HpackContext ctx = new HpackContext(38*5);
|
||||||
|
|
||||||
|
HttpField methodPost = new HttpField(":method","POST");
|
||||||
|
HttpField[] field =
|
||||||
|
{
|
||||||
|
new HttpField("fo0","b0r"),
|
||||||
|
new HttpField("fo1","b1r"),
|
||||||
|
new HttpField("fo2","b2r"),
|
||||||
|
new HttpField("fo3","b3r"),
|
||||||
|
new HttpField("fo4","b4r"),
|
||||||
|
new HttpField("fo5","b5r"),
|
||||||
|
new HttpField("fo6","b6r"),
|
||||||
|
new HttpField("fo7","b7r"),
|
||||||
|
new HttpField("fo8","b8r"),
|
||||||
|
new HttpField("fo9","b9r"),
|
||||||
|
new HttpField("foA","bAr"),
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry[] entry = new Entry[100];
|
||||||
|
|
||||||
|
// Lookup the index of a static field
|
||||||
|
assertEquals(0,ctx.size());
|
||||||
|
assertEquals(":authority",ctx.get(1).getHttpField().getName());
|
||||||
|
assertEquals(3,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62));
|
||||||
|
|
||||||
|
// Add a single entry
|
||||||
|
entry[0]=ctx.add(field[0]);
|
||||||
|
|
||||||
|
// Check new entry is 1
|
||||||
|
assertEquals(1,ctx.size());
|
||||||
|
assertEquals(1,ctx.index(entry[0]));
|
||||||
|
assertEquals(entry[0],ctx.get(1));
|
||||||
|
|
||||||
|
// and statics have moved up 1
|
||||||
|
assertEquals(":authority",ctx.get(1+1).getHttpField().getName());
|
||||||
|
assertEquals(3+1,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+1).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+1).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+1));
|
||||||
|
|
||||||
|
|
||||||
|
// Add 4 more entries
|
||||||
|
for (int i=1;i<=4;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
// Check newest entry is at 1 oldest at 5
|
||||||
|
assertEquals(5,ctx.size());
|
||||||
|
int index=5;
|
||||||
|
for (int i=0;i<=4;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and statics have moved up 5
|
||||||
|
assertEquals(":authority",ctx.get(1+5).getHttpField().getName());
|
||||||
|
assertEquals(3+5,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+5).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+5));
|
||||||
|
|
||||||
|
// add 1 more entry and this should cause an eviction!
|
||||||
|
entry[5]=ctx.add(field[5]);
|
||||||
|
|
||||||
|
// Check newest entry is at 1 oldest at 5
|
||||||
|
index=5;
|
||||||
|
for (int i=1;i<=5;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
// check entry 0 evicted
|
||||||
|
assertNull(ctx.get(field[0]));
|
||||||
|
assertEquals(0,ctx.index(entry[0]));
|
||||||
|
|
||||||
|
// and statics have moved up just 5
|
||||||
|
assertEquals(":authority",ctx.get(1+5).getHttpField().getName());
|
||||||
|
assertEquals(3+5,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+5).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+5));
|
||||||
|
|
||||||
|
// Add 4 more entries
|
||||||
|
for (int i=6;i<=9;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
// Check newest entry is at 1 oldest at 5
|
||||||
|
index=5;
|
||||||
|
for (int i=5;i<=9;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
// check entry 0-4 evicted
|
||||||
|
for (int i=0;i<=4;i++)
|
||||||
|
{
|
||||||
|
assertNull(ctx.get(field[i]));
|
||||||
|
assertEquals(0,ctx.index(entry[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add new entries enough so that array queue will wrap
|
||||||
|
for (int i=10;i<=52;i++)
|
||||||
|
entry[i]=ctx.add(new HttpField("n"+i,"v"+i));
|
||||||
|
|
||||||
|
index=5;
|
||||||
|
for (int i=48;i<=52;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefSetAddStatic()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(4096);
|
||||||
|
|
||||||
|
HttpField methodGet = new HttpField(":method","GET");
|
||||||
|
Entry entry = ctx.get(methodGet);
|
||||||
|
ctx.addToRefSet(entry);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(IllegalStateException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefSetAddEvicted()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(38);
|
||||||
|
HttpField field0 = new HttpField("foo","bar");
|
||||||
|
HttpField field1 = new HttpField("xxx","yyy");
|
||||||
|
Entry entry = ctx.add(field0);
|
||||||
|
ctx.add(field1);
|
||||||
|
ctx.addToRefSet(entry);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(IllegalStateException e)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefSetEmptyIteration()
|
||||||
|
{
|
||||||
|
HpackContext ctx = new HpackContext(4096);
|
||||||
|
for (Entry entry: ctx.getReferenceSet() )
|
||||||
|
fail("unexpected:"+entry);
|
||||||
|
Iterator<Entry> iter = ctx.iterateReferenceSet();
|
||||||
|
assertFalse(iter.hasNext());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
iter.next();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(NoSuchElementException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
iter.remove();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
catch(NoSuchElementException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefSet()
|
||||||
|
{
|
||||||
|
// Only enough space for 5 entries
|
||||||
|
HpackContext ctx = new HpackContext(38*5);
|
||||||
|
|
||||||
|
HttpField[] field =
|
||||||
|
{
|
||||||
|
new HttpField("fo0","b0r"),
|
||||||
|
new HttpField("fo1","b1r"),
|
||||||
|
new HttpField("fo2","b2r"),
|
||||||
|
new HttpField("fo3","b3r"),
|
||||||
|
new HttpField("fo4","b4r"),
|
||||||
|
new HttpField("fo5","b5r"),
|
||||||
|
new HttpField("fo6","b6r"),
|
||||||
|
new HttpField("fo7","b7r"),
|
||||||
|
new HttpField("fo8","b8r"),
|
||||||
|
new HttpField("fo9","b9r"),
|
||||||
|
new HttpField("foA","bAr"),
|
||||||
|
};
|
||||||
|
Entry[] entry = new Entry[field.length];
|
||||||
|
|
||||||
|
// Add 5 entries
|
||||||
|
for (int i=0;i<=4;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
// Add 3 entries to reference set
|
||||||
|
ctx.addToRefSet(ctx.get(3));
|
||||||
|
ctx.addToRefSet(ctx.get(1));
|
||||||
|
ctx.addToRefSet(ctx.get(5));
|
||||||
|
|
||||||
|
// iterate ref set
|
||||||
|
HashSet<HttpField> fields = new HashSet<>();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(3,fields.size());
|
||||||
|
assertTrue(fields.contains(field[0]));
|
||||||
|
assertTrue(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
// duplicate add ignored
|
||||||
|
ctx.addToRefSet(ctx.get(1));
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(3,fields.size());
|
||||||
|
assertTrue(fields.contains(field[0]));
|
||||||
|
assertTrue(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
// remove entry
|
||||||
|
ctx.get(3).removeFromRefSet();
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(2,fields.size());
|
||||||
|
assertTrue(fields.contains(field[0]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
// iterator remove
|
||||||
|
Iterator<Entry> iter=ctx.iterateReferenceSet();
|
||||||
|
iter.next();
|
||||||
|
iter.remove();
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(1,fields.size());
|
||||||
|
|
||||||
|
// Add 5 new entries to cause evictions
|
||||||
|
for (int i=5;i<=9;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(0,fields.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResize()
|
||||||
|
{
|
||||||
|
// Only enough space for 5 entries
|
||||||
|
HpackContext ctx = new HpackContext(38*5);
|
||||||
|
HttpField methodPost = new HttpField(":method","POST");
|
||||||
|
|
||||||
|
HttpField[] field =
|
||||||
|
{
|
||||||
|
new HttpField("fo0","b0r"),
|
||||||
|
new HttpField("fo1","b1r"),
|
||||||
|
new HttpField("fo2","b2r"),
|
||||||
|
new HttpField("fo3","b3r"),
|
||||||
|
new HttpField("fo4","b4r"),
|
||||||
|
new HttpField("fo5","b5r"),
|
||||||
|
new HttpField("fo6","b6r"),
|
||||||
|
new HttpField("fo7","b7r"),
|
||||||
|
new HttpField("fo8","b8r"),
|
||||||
|
new HttpField("fo9","b9r"),
|
||||||
|
new HttpField("foA","bAr"),
|
||||||
|
};
|
||||||
|
Entry[] entry = new Entry[field.length];
|
||||||
|
|
||||||
|
// Add 5 entries
|
||||||
|
for (int i=0;i<=4;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
assertEquals(5,ctx.size());
|
||||||
|
|
||||||
|
// check indexes
|
||||||
|
int index=5;
|
||||||
|
for (int i=0;i<=4;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and statics have moved up 5
|
||||||
|
assertEquals(":authority",ctx.get(1+5).getHttpField().getName());
|
||||||
|
assertEquals(3+5,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+5).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+5).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+5));
|
||||||
|
|
||||||
|
|
||||||
|
// Add 3 entries to reference set
|
||||||
|
ctx.addToRefSet(ctx.get(3));
|
||||||
|
ctx.addToRefSet(ctx.get(1));
|
||||||
|
ctx.addToRefSet(ctx.get(5));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// iterate ref set
|
||||||
|
HashSet<HttpField> fields = new HashSet<>();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(3,fields.size());
|
||||||
|
assertTrue(fields.contains(field[0]));
|
||||||
|
assertTrue(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
// resize so that only 2 entries may be held
|
||||||
|
ctx.resize(38*2);
|
||||||
|
assertEquals(2,ctx.size());
|
||||||
|
|
||||||
|
// check indexes
|
||||||
|
index=2;
|
||||||
|
for (int i=3;i<=4;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and statics have moved up 2
|
||||||
|
assertEquals(":authority",ctx.get(1+2).getHttpField().getName());
|
||||||
|
assertEquals(3+2,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+2).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+2));
|
||||||
|
|
||||||
|
// check reference set
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(1,fields.size());
|
||||||
|
assertFalse(fields.contains(field[0]));
|
||||||
|
assertFalse(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
|
||||||
|
// resize so that 6.5 entries may be held
|
||||||
|
ctx.resize(38*6+19);
|
||||||
|
assertEquals(2,ctx.size());
|
||||||
|
|
||||||
|
|
||||||
|
// check indexes
|
||||||
|
index=2;
|
||||||
|
for (int i=3;i<=4;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and statics have moved up 2
|
||||||
|
assertEquals(":authority",ctx.get(1+2).getHttpField().getName());
|
||||||
|
assertEquals(3+2,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+2).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+2).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+2));
|
||||||
|
|
||||||
|
// check reference set
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(1,fields.size());
|
||||||
|
assertFalse(fields.contains(field[0]));
|
||||||
|
assertFalse(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
|
||||||
|
// Add 5 entries
|
||||||
|
for (int i=5;i<=9;i++)
|
||||||
|
entry[i]=ctx.add(field[i]);
|
||||||
|
|
||||||
|
assertEquals(6,ctx.size());
|
||||||
|
|
||||||
|
// check indexes
|
||||||
|
index=6;
|
||||||
|
for (int i=4;i<=9;i++)
|
||||||
|
{
|
||||||
|
assertEquals(index,ctx.index(entry[i]));
|
||||||
|
assertEquals(entry[i],ctx.get(index));
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and statics have moved up 6
|
||||||
|
assertEquals(":authority",ctx.get(1+6).getHttpField().getName());
|
||||||
|
assertEquals(3+6,ctx.index(ctx.get(methodPost)));
|
||||||
|
assertEquals(methodPost,ctx.get(3+6).getHttpField());
|
||||||
|
assertEquals("www-authenticate",ctx.get(61+6).getHttpField().getName());
|
||||||
|
assertEquals(null,ctx.get(62+6));
|
||||||
|
|
||||||
|
// check reference set
|
||||||
|
fields.clear();
|
||||||
|
for (Entry e: ctx.getReferenceSet() )
|
||||||
|
fields.add(e.getHttpField());
|
||||||
|
assertEquals(1,fields.size());
|
||||||
|
assertFalse(fields.contains(field[0]));
|
||||||
|
assertFalse(fields.contains(field[2]));
|
||||||
|
assertTrue(fields.contains(field[4]));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,17 @@ public class HuffmanTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecodeTrailingFF() throws Exception
|
||||||
|
{
|
||||||
|
for (String[] test:tests)
|
||||||
|
{
|
||||||
|
byte[] encoded=TypeUtil.fromHexString(test[1]+"FF");
|
||||||
|
String decoded=Huffman.decode(ByteBuffer.wrap(encoded));
|
||||||
|
Assert.assertEquals(test[0],test[2],decoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncode() throws Exception
|
public void testEncode() throws Exception
|
||||||
{
|
{
|
||||||
@ -62,8 +73,37 @@ public class HuffmanTest
|
|||||||
BufferUtil.flipToFlush(buf,pos);
|
BufferUtil.flipToFlush(buf,pos);
|
||||||
String encoded=TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase();
|
String encoded=TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase();
|
||||||
Assert.assertEquals(test[0],test[1],encoded);
|
Assert.assertEquals(test[0],test[1],encoded);
|
||||||
|
Assert.assertEquals(test[1].length()/2,Huffman.octetsNeeded(test[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncode8859Only() throws Exception
|
||||||
|
{
|
||||||
|
char bad[] = {(char)128,(char)0,(char)-1,' '-1};
|
||||||
|
for (int i=0;i<bad.length;i++)
|
||||||
|
{
|
||||||
|
String s="bad '"+bad[i]+"'";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Huffman.octetsNeeded(s);
|
||||||
|
Assert.fail("i="+i);
|
||||||
|
}
|
||||||
|
catch(IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Huffman.encode(BufferUtil.allocate(32),s);
|
||||||
|
Assert.fail("i="+i);
|
||||||
|
}
|
||||||
|
catch(IllegalArgumentException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ public class NBitIntegerTest
|
|||||||
assertEquals(0,NBitInteger.octectsNeeded(5,10));
|
assertEquals(0,NBitInteger.octectsNeeded(5,10));
|
||||||
assertEquals(2,NBitInteger.octectsNeeded(5,1337));
|
assertEquals(2,NBitInteger.octectsNeeded(5,1337));
|
||||||
assertEquals(1,NBitInteger.octectsNeeded(8,42));
|
assertEquals(1,NBitInteger.octectsNeeded(8,42));
|
||||||
|
assertEquals(3,NBitInteger.octectsNeeded(8,1337));
|
||||||
|
|
||||||
assertEquals(0,NBitInteger.octectsNeeded(6,62));
|
assertEquals(0,NBitInteger.octectsNeeded(6,62));
|
||||||
assertEquals(1,NBitInteger.octectsNeeded(6,63));
|
assertEquals(1,NBitInteger.octectsNeeded(6,63));
|
||||||
@ -64,19 +65,31 @@ public class NBitIntegerTest
|
|||||||
testEncode(6,63+0x00+0x80*0x80, "3f808001");
|
testEncode(6,63+0x00+0x80*0x80, "3f808001");
|
||||||
testEncode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
|
testEncode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
|
||||||
testEncode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
|
testEncode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
|
||||||
|
|
||||||
|
testEncode(8,0,"00");
|
||||||
|
testEncode(8,1,"01");
|
||||||
|
testEncode(8,128,"80");
|
||||||
|
testEncode(8,254,"Fe");
|
||||||
|
testEncode(8,255,"Ff00");
|
||||||
|
testEncode(8,255+1,"Ff01");
|
||||||
|
testEncode(8,255+0x7e,"Ff7e");
|
||||||
|
testEncode(8,255+0x7f,"Ff7f");
|
||||||
|
testEncode(8,255+0x80,"Ff8001");
|
||||||
|
testEncode(8,255+0x00+0x80*0x80,"Ff808001");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEncode(int n,int i,String expected)
|
public void testEncode(int n,int i,String expected)
|
||||||
{
|
{
|
||||||
ByteBuffer buf = BufferUtil.allocate(16);
|
ByteBuffer buf = BufferUtil.allocate(16);
|
||||||
int p=BufferUtil.flipToFill(buf);
|
int p=BufferUtil.flipToFill(buf);
|
||||||
buf.put((byte)0x00);
|
if (n<8)
|
||||||
|
buf.put((byte)0x00);
|
||||||
NBitInteger.encode(buf,n,i);
|
NBitInteger.encode(buf,n,i);
|
||||||
BufferUtil.flipToFlush(buf,p);
|
BufferUtil.flipToFlush(buf,p);
|
||||||
String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
|
String r=TypeUtil.toHexString(BufferUtil.toArray(buf));
|
||||||
assertEquals(expected,r);
|
assertEquals(expected,r);
|
||||||
|
|
||||||
assertEquals(expected.length()/2,1+NBitInteger.octectsNeeded(n,i));
|
assertEquals(expected.length()/2,(n<8?1:0)+NBitInteger.octectsNeeded(n,i));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -98,6 +111,17 @@ public class NBitIntegerTest
|
|||||||
testDecode(6,63+0x00+0x80*0x80, "3f808001");
|
testDecode(6,63+0x00+0x80*0x80, "3f808001");
|
||||||
testDecode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
|
testDecode(6,63+0x7f+0x80*0x80*0x7f,"3fFf807f");
|
||||||
testDecode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
|
testDecode(6,63+0x00+0x80*0x80*0x80,"3f80808001");
|
||||||
|
|
||||||
|
testDecode(8,0,"00");
|
||||||
|
testDecode(8,1,"01");
|
||||||
|
testDecode(8,128,"80");
|
||||||
|
testDecode(8,254,"Fe");
|
||||||
|
testDecode(8,255,"Ff00");
|
||||||
|
testDecode(8,255+1,"Ff01");
|
||||||
|
testDecode(8,255+0x7e,"Ff7e");
|
||||||
|
testDecode(8,255+0x7f,"Ff7f");
|
||||||
|
testDecode(8,255+0x80,"Ff8001");
|
||||||
|
testDecode(8,255+0x00+0x80*0x80,"Ff808001");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -393,16 +393,22 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected void growUnsafe(int newCapacity)
|
protected void resizeUnsafe(int newCapacity)
|
||||||
{
|
{
|
||||||
|
newCapacity = Math.max(newCapacity,_size);
|
||||||
Object[] elements = new Object[newCapacity];
|
Object[] elements = new Object[newCapacity];
|
||||||
|
|
||||||
int split = _elements.length - _nextE;
|
if (_size>0)
|
||||||
if (split > 0)
|
{
|
||||||
System.arraycopy(_elements, _nextE, elements, 0, split);
|
if (_nextSlot>_nextE)
|
||||||
if (_nextE != 0)
|
System.arraycopy(_elements, _nextE, elements, 0, _size);
|
||||||
System.arraycopy(_elements, 0, elements, split, _nextSlot);
|
else
|
||||||
|
{
|
||||||
|
int split = _elements.length - _nextE;
|
||||||
|
System.arraycopy(_elements, _nextE, elements, 0, split);
|
||||||
|
System.arraycopy(_elements, 0, elements, split, _nextSlot);
|
||||||
|
}
|
||||||
|
}
|
||||||
_elements = elements;
|
_elements = elements;
|
||||||
_nextE = 0;
|
_nextE = 0;
|
||||||
_nextSlot = _size;
|
_nextSlot = _size;
|
||||||
@ -413,8 +419,7 @@ public class ArrayQueue<E> extends AbstractList<E> implements Queue<E>
|
|||||||
{
|
{
|
||||||
if (_growCapacity <= 0)
|
if (_growCapacity <= 0)
|
||||||
return false;
|
return false;
|
||||||
growUnsafe(_elements.length+_growCapacity);
|
resizeUnsafe(_elements.length+_growCapacity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user