@@ -22,23 +22,14 @@ import { concatBuffers } from '../src/concat_buffers'
22
22
import { Buffer } from 'buffer'
23
23
import * as fixtures from './fixtures'
24
24
25
- describe ( 'readElements' , ( ) => {
26
- it ( 'should be able to find one element' , ( ) => {
27
- const len = Buffer . alloc ( 2 )
28
- len . writeUInt16BE ( 4 , 0 )
29
- const data = new Uint8Array ( [ ...Buffer . from ( 'data' ) ] )
30
- const buff = concatBuffers ( len , data )
31
- const info = readElements ( 1 , buff , 0 )
32
- if ( info === false ) throw new Error ( 'Fail' )
33
- expect ( info . elements ) . to . be . instanceof ( Array )
34
- expect ( info . elements . length ) . to . eql ( 1 )
35
- expect ( info . elements [ 0 ] ) . to . deep . equal ( data )
36
- expect ( info . readPos ) . to . eql ( 6 )
37
- } )
25
+ function randomNat ( limit : number ) : number {
26
+ return Math . floor ( Math . random ( ) * limit )
27
+ }
38
28
39
- it ( 'should be able to handle multiple elements' , ( ) => {
29
+ describe ( 'readElements' , ( ) => {
30
+ it ( 'should be able to handle multiple elements containing multiple fields without padding' , ( ) => {
40
31
const utf8DataStrings = [
41
- 'some utf8 information' , '\u00bd + \u00bc = \u00be' , 'to encode '
32
+ 'here' , 'is' , ' some' , ' utf8' , ' information', '\u00bd + \u00bc = \u00be'
42
33
]
43
34
const buffData = utf8DataStrings . map ( str => new Uint8Array ( [ ...Buffer . from ( str ) ] ) )
44
35
const buff = concatBuffers ( ...buffData . map ( bufStr => {
@@ -47,75 +38,93 @@ describe('readElements', () => {
47
38
return concatBuffers ( len , bufStr )
48
39
} ) )
49
40
50
- const info = readElements ( 3 , buff , 0 )
51
-
52
- if ( info === false ) throw new Error ( 'Fail' )
53
- expect ( info . elements ) . to . be . instanceof ( Array )
54
- expect ( info . elements . length ) . to . eql ( 3 )
55
- expect ( info . elements [ 0 ] ) . to . deep . equal ( buffData [ 0 ] )
56
- expect ( info . elements [ 1 ] ) . to . deep . equal ( buffData [ 1 ] )
57
- expect ( info . elements [ 2 ] ) . to . deep . equal ( buffData [ 2 ] )
58
- expect ( Buffer . from ( info . elements [ 0 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 0 ] )
59
- expect ( Buffer . from ( info . elements [ 1 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 1 ] )
60
- expect ( Buffer . from ( info . elements [ 2 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 2 ] )
61
- expect ( info . readPos ) . to . eql ( 48 )
41
+ /* The elements in the buffer can be arranged in several ways.
42
+ * For example, we can think of them as six elements with one
43
+ * field each, or as three elements with two fields each.
44
+ */
45
+ const dimensions = [ [ 1 , 6 ] , [ 2 , 3 ] , [ 3 , 2 ] , [ 6 , 1 ] ]
46
+
47
+ dimensions . map ( ( [ elementCount , fieldsPerElement ] ) => {
48
+ const info = readElements ( elementCount , fieldsPerElement , buff )
49
+
50
+ if ( info === false ) throw new Error ( 'Fail' )
51
+ let elements = info . elements
52
+ expect ( elements ) . to . be . instanceof ( Array )
53
+ expect ( elements . length ) . to . eql ( elementCount )
54
+
55
+ for ( let eCount = 0 ; eCount < elementCount ; eCount ++ ) {
56
+ let element = info . elements [ eCount ]
57
+ expect ( element ) . to . be . instanceof ( Array )
58
+ expect ( element . length ) . to . eql ( fieldsPerElement )
59
+ for ( let fCount = 0 ; fCount < fieldsPerElement ; fCount ++ ) {
60
+ let field = element [ fCount ]
61
+ expect ( field ) . to . deep . equal ( buffData [ eCount * fieldsPerElement + fCount ] )
62
+ expect ( Buffer . from ( field ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ eCount * fieldsPerElement + fCount ] )
63
+ }
64
+ }
65
+
66
+ expect ( info . readPos ) . to . eql ( buff . byteLength )
67
+ } )
62
68
} )
63
69
64
- it ( 'should be able to handle multiple elements when not reading from the beginning ' , ( ) => {
65
- const utf8DataStrings = [
66
- 'some utf8 information' , '\u00bd + \u00bc = \u00be' , 'to encode'
67
- ]
70
+ it ( 'should be able to handle multiple elements containing multiple fields with various padding ' , ( ) => {
71
+ let numberOfRuns = 16
72
+ const maxPaddingLength = 1024
73
+ const utf8DataStrings = [ 'here' , 'is' , 'some' , 'utf8' , 'information' , '\u00bd + \u00bc = \u00be' ]
68
74
const buffData = utf8DataStrings . map ( str => new Uint8Array ( [ ...Buffer . from ( str ) ] ) )
69
- const padding = Buffer . alloc ( 10 )
70
- const buff = concatBuffers ( padding , ...buffData . map ( bufStr => {
75
+ const mainBuffer = concatBuffers ( ...buffData . map ( bufStr => {
71
76
const len = Buffer . alloc ( 2 )
72
77
len . writeUInt16BE ( bufStr . byteLength , 0 )
73
78
return concatBuffers ( len , bufStr )
74
79
} ) )
75
80
76
- const info = readElements ( 3 , buff , padding . length )
77
-
78
- if ( info === false ) throw new Error ( 'Fail' )
79
- expect ( info . elements ) . to . be . instanceof ( Array )
80
- expect ( info . elements . length ) . to . eql ( 3 )
81
- expect ( info . elements [ 0 ] ) . to . deep . equal ( buffData [ 0 ] )
82
- expect ( info . elements [ 1 ] ) . to . deep . equal ( buffData [ 1 ] )
83
- expect ( info . elements [ 2 ] ) . to . deep . equal ( buffData [ 2 ] )
84
- expect ( Buffer . from ( info . elements [ 0 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 0 ] )
85
- expect ( Buffer . from ( info . elements [ 1 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 1 ] )
86
- expect ( Buffer . from ( info . elements [ 2 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 2 ] )
87
- expect ( info . readPos ) . to . eql ( 58 )
81
+ const dimensions = [ [ 1 , 6 ] , [ 2 , 3 ] , [ 3 , 2 ] , [ 6 , 1 ] ]
82
+
83
+ while ( numberOfRuns -- ) {
84
+ let leftPadding = Buffer . alloc ( randomNat ( maxPaddingLength ) )
85
+ let rightPadding = Buffer . alloc ( randomNat ( maxPaddingLength ) )
86
+ let buff = concatBuffers ( leftPadding , mainBuffer , rightPadding )
87
+
88
+ dimensions . map ( ( [ elementCount , fieldsPerElement ] ) => {
89
+ const info = readElements ( elementCount , fieldsPerElement , buff , leftPadding . byteLength )
90
+
91
+ if ( info === false ) throw new Error ( 'Fail' )
92
+ let elements = info . elements
93
+ expect ( elements ) . to . be . instanceof ( Array )
94
+ expect ( elements . length ) . to . eql ( elementCount )
95
+
96
+ for ( let eCount = 0 ; eCount < elementCount ; eCount ++ ) {
97
+ let element = info . elements [ eCount ]
98
+ expect ( element ) . to . be . instanceof ( Array )
99
+ expect ( element . length ) . to . eql ( fieldsPerElement )
100
+ for ( let fCount = 0 ; fCount < fieldsPerElement ; fCount ++ ) {
101
+ let field = element [ fCount ]
102
+ expect ( field ) . to . deep . equal ( buffData [ eCount * fieldsPerElement + fCount ] )
103
+ expect ( Buffer . from ( field ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ eCount * fieldsPerElement + fCount ] )
104
+ }
105
+ }
106
+
107
+ expect ( info . readPos ) . to . eql ( leftPadding . byteLength + mainBuffer . byteLength )
108
+ } )
109
+ }
88
110
} )
89
111
90
- it ( 'should be able to handle multiple elements with padding on both sides' , ( ) => {
91
- const utf8DataStrings = [
92
- 'some utf8 information' , '\u00bd + \u00bc = \u00be' , 'to encode'
93
- ]
94
- const buffData = utf8DataStrings . map ( str => new Uint8Array ( [ ...Buffer . from ( str ) ] ) )
95
- const padding = Buffer . alloc ( 10 )
96
- const buff = concatBuffers ( padding , ...buffData . map ( bufStr => {
97
- const len = Buffer . alloc ( 2 )
98
- len . writeUInt16BE ( bufStr . byteLength , 0 )
99
- return concatBuffers ( len , bufStr )
100
- } ) , padding )
101
-
102
- const info = readElements ( 3 , buff , padding . length )
103
-
104
- if ( info === false ) throw new Error ( 'Fail' )
105
- expect ( info . elements ) . to . be . instanceof ( Array )
106
- expect ( info . elements . length ) . to . eql ( 3 )
107
- expect ( info . elements [ 0 ] ) . to . deep . equal ( buffData [ 0 ] )
108
- expect ( info . elements [ 1 ] ) . to . deep . equal ( buffData [ 1 ] )
109
- expect ( info . elements [ 2 ] ) . to . deep . equal ( buffData [ 2 ] )
110
- expect ( Buffer . from ( info . elements [ 0 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 0 ] )
111
- expect ( Buffer . from ( info . elements [ 1 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 1 ] )
112
- expect ( Buffer . from ( info . elements [ 2 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 2 ] )
113
- expect ( info . readPos ) . to . eql ( 58 )
112
+ it ( 'Precondition: readPos must be non-negative and within the byte length of the buffer given.' , ( ) => {
113
+ const buff = new Uint8Array ( 32 )
114
+ const readPosBeyondBuff = buff . byteLength + 1
115
+ expect ( ( ) => readElements ( 1 , 1 , buff , readPosBeyondBuff ) ) . to . throw ( )
116
+ } )
117
+
118
+ it ( 'Precondition: elementCount and fieldsPerElement must be non-negative.' , ( ) => {
119
+ const buff = new Uint8Array ( 32 )
120
+ expect ( ( ) => readElements ( - 1 , 1 , buff ) ) . to . throw ( )
121
+ expect ( ( ) => readElements ( 1 , - 1 , buff ) ) . to . throw ( )
122
+ expect ( ( ) => readElements ( - 1 , - 1 , buff ) ) . to . throw ( )
114
123
} )
115
124
116
125
it ( 'Check for early return (Postcondition): Enough data must exist to read the Uint16 length value.; Check for early return (Postcondition): Enough data must exist length of the value.' , ( ) => {
117
126
const utf8DataStrings = [
118
- 'some utf8 information' , '\u00bd + \u00bc = \u00be' , 'to encode '
127
+ 'here' , 'is' , ' some' , ' utf8' , ' information', '\u00bd + \u00bc = \u00be'
119
128
]
120
129
const buffData = utf8DataStrings . map ( str => new Uint8Array ( [ ...Buffer . from ( str ) ] ) )
121
130
const buff = concatBuffers ( ...buffData . map ( bufStr => {
@@ -124,35 +133,13 @@ describe('readElements', () => {
124
133
return concatBuffers ( len , bufStr )
125
134
} ) )
126
135
127
- // By testing every combination of byte length possible
128
- // Both loop invariants are covered.
129
- for ( let i = 0 ; buff . byteLength > i ; i ++ ) {
130
- const info = readElements ( 3 , buff . slice ( 0 , i ) , 0 )
131
- expect ( info ) . to . eql ( false )
132
- }
133
- // Engage pedantry...
134
- const info = readElements ( 3 , buff . slice ( 0 , buff . byteLength ) , 0 )
135
- if ( info === false ) throw new Error ( 'Fail' )
136
- expect ( info . elements ) . to . be . instanceof ( Array )
137
- expect ( info . elements . length ) . to . eql ( 3 )
138
- expect ( info . elements [ 0 ] ) . to . deep . equal ( buffData [ 0 ] )
139
- expect ( info . elements [ 1 ] ) . to . deep . equal ( buffData [ 1 ] )
140
- expect ( info . elements [ 2 ] ) . to . deep . equal ( buffData [ 2 ] )
141
- expect ( Buffer . from ( info . elements [ 0 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 0 ] )
142
- expect ( Buffer . from ( info . elements [ 1 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 1 ] )
143
- expect ( Buffer . from ( info . elements [ 2 ] ) . toString ( ) ) . to . deep . equal ( utf8DataStrings [ 2 ] )
144
- expect ( info . readPos ) . to . eql ( 48 )
145
- } )
146
-
147
- it ( 'Precondition: readElements readPos must be within the byte length of the buffer given.' , ( ) => {
148
- const buff = new Uint8Array ( 32 )
149
- const readPosBeyondBuff = buff . byteLength + 1
150
- expect ( ( ) => readElements ( 1 , buff , readPosBeyondBuff ) ) . to . throw ( )
151
- } )
136
+ /* Will return false when trying to read the length of the seventh element */
137
+ const infoFalse1 = readElements ( 1 , 7 , buff )
138
+ expect ( infoFalse1 ) . to . equal ( false )
152
139
153
- it ( 'Precondition: elementCount must not be negative.' , ( ) => {
154
- const buff = new Uint8Array ( 32 )
155
- expect ( ( ) => readElements ( - 1 , buff ) ) . to . throw ( )
140
+ /* Will return false when trying to read the sixth element */
141
+ const infoFalse2 = readElements ( 1 , 6 , buff . slice ( 0 , buff . byteLength - 1 ) )
142
+ expect ( infoFalse2 ) . to . equal ( false )
156
143
} )
157
144
158
145
it ( 'ArrayBuffer for a Uint8Array or Buffer may be larger than the Uint8Array or Buffer that it is a view over is.' , ( ) => {
@@ -162,12 +149,12 @@ describe('readElements', () => {
162
149
* read position past the length and count should succeed.
163
150
*/
164
151
const buff = fixtures . basicEncryptionContext ( )
165
- expect ( readElements ( 4 , buff , 0 ) ) . to . equal ( false )
166
- expect ( readElements ( 4 , buff , 4 ) ) . to . not . equal ( false )
152
+ expect ( readElements ( 4 , 1 , buff , 0 ) ) . to . equal ( false )
153
+ expect ( readElements ( 4 , 1 , buff , 4 ) ) . to . not . equal ( false )
167
154
/* Given this I can use this to construct a new view of part of the
168
155
* ArrayBuffer to simulate a large ArrayBuffer that is sliced
169
156
* into parts for efficiency. */
170
157
const sharingArrayBuffer = new Uint8Array ( buff . buffer , 4 , buff . byteLength - 4 )
171
- expect ( readElements ( 4 , sharingArrayBuffer ) ) . to . not . equal ( false )
158
+ expect ( readElements ( 4 , 1 , sharingArrayBuffer ) ) . to . not . equal ( false )
172
159
} )
173
160
} )
0 commit comments