11'use strict' ;
2+ const debug = require ( 'debug' ) ( 'serialport:bindings:mock' ) ;
23const Buffer = require ( 'safe-buffer' ) . Buffer ;
34const BaseBinding = require ( './base' ) ;
45
56let ports = { } ;
7+ let serialNumber = 0 ;
68
79function resolveNextTick ( ) {
810 return new Promise ( resolve => process . nextTick ( resolve ) ) ;
@@ -15,6 +17,7 @@ class MockBinding extends BaseBinding {
1517 this . isOpen = false ;
1618 this . port = null ;
1719 this . lastWrite = null ;
20+ this . recording = new Buffer ( 0 ) ;
1821 this . pendingWrite = null ;
1922 }
2023
@@ -25,25 +28,29 @@ class MockBinding extends BaseBinding {
2528
2629 // Create a mock port
2730 static createPort ( path , opt ) {
31+ serialNumber ++ ;
2832 opt = Object . assign ( {
29- echo : true ,
33+ echo : false ,
34+ record : false ,
3035 readyData : Buffer . from ( 'READY' )
3136 } , opt ) ;
3237
3338 ports [ path ] = {
3439 data : Buffer . alloc ( 0 ) ,
3540 echo : opt . echo ,
36- readyData : opt . readyData ,
41+ record : opt . record ,
42+ readyData : Buffer . from ( opt . readyData ) ,
3743 info : {
3844 comName : path ,
3945 manufacturer : 'The J5 Robotics Company' ,
40- serialNumber : undefined ,
46+ serialNumber,
4147 pnpId : undefined ,
4248 locationId : undefined ,
4349 vendorId : undefined ,
4450 productId : undefined
4551 }
4652 } ;
53+ debug ( serialNumber , 'created port' , JSON . stringify ( { path, opt } ) ) ;
4754 }
4855
4956 static list ( ) {
@@ -58,21 +65,27 @@ class MockBinding extends BaseBinding {
5865 if ( ! this . isOpen ) {
5966 throw new Error ( 'Port must be open to pretend to receive data' ) ;
6067 }
68+ if ( ! Buffer . isBuffer ( data ) ) {
69+ data = Buffer . from ( data ) ;
70+ }
71+ debug ( this . serialNumber , 'emitting data - pending read:' , Boolean ( this . pendingRead ) ) ;
6172 this . port . data = Buffer . concat ( [ this . port . data , data ] ) ;
62-
6373 if ( this . pendingRead ) {
6474 process . nextTick ( this . pendingRead ) ;
6575 this . pendingRead = null ;
6676 }
6777 }
6878
6979 open ( path , opt ) {
80+ debug ( null , `opening path ${ path } ` ) ;
7081 const port = this . port = ports [ path ] ;
7182 return super . open ( path , opt )
83+ . then ( resolveNextTick )
7284 . then ( ( ) => {
7385 if ( ! port ) {
7486 return Promise . reject ( new Error ( `Port does not exist - please call MockBinding.createPort('${ path } ') first` ) ) ;
7587 }
88+ this . serialNumber = port . info . serialNumber ;
7689
7790 if ( port . openOpt && port . openOpt . lock ) {
7891 return Promise . reject ( new Error ( 'Port is locked cannot open' ) ) ;
@@ -84,6 +97,7 @@ class MockBinding extends BaseBinding {
8497
8598 port . openOpt = Object . assign ( { } , opt ) ;
8699 this . isOpen = true ;
100+ debug ( this . serialNumber , 'port is open' ) ;
87101 if ( port . echo ) {
88102 process . nextTick ( ( ) => {
89103 if ( this . isOpen ) { this . emitData ( port . readyData ) }
@@ -94,6 +108,7 @@ class MockBinding extends BaseBinding {
94108
95109 close ( ) {
96110 const port = this . port ;
111+ debug ( this . serialNumber , 'closing port' ) ;
97112 if ( ! port ) {
98113 return Promise . reject ( new Error ( 'close' ) ) ;
99114 }
@@ -104,12 +119,15 @@ class MockBinding extends BaseBinding {
104119 // reset data on close
105120 port . data = Buffer . alloc ( 0 ) ;
106121
122+ debug ( this . serialNumber , 'port is closed' ) ;
107123 delete this . port ;
124+ delete this . serialNumber ;
108125 this . isOpen = false ;
109126 } ) ;
110127 }
111128
112129 read ( buffer , offset , length ) {
130+ debug ( this . serialNumber , 'reading' , length , 'bytes' ) ;
113131 return super . read ( buffer , offset , length )
114132 . then ( resolveNextTick ( ) )
115133 . then ( ( ) => {
@@ -124,42 +142,52 @@ class MockBinding extends BaseBinding {
124142 const data = this . port . data . slice ( 0 , length ) ;
125143 const readLength = data . copy ( buffer , offset ) ;
126144 this . port . data = this . port . data . slice ( length ) ;
127-
145+ debug ( this . serialNumber , 'read' , readLength , 'bytes' ) ;
128146 return readLength ;
129147 } ) ;
130148 }
131149
132150 write ( buffer ) {
151+ debug ( this . serialNumber , 'writing' ) ;
152+ if ( this . pendingWrite ) {
153+ throw new Error ( 'Overlapping writes are not supported and should be queued by the serialport object' ) ;
154+ }
133155 this . pendingWrite = super . write ( buffer )
134- . then ( resolveNextTick ( ) )
156+ . then ( resolveNextTick )
135157 . then ( ( ) => {
136158 if ( ! this . isOpen ) {
137159 throw new Error ( 'Write canceled' ) ;
138160 }
139161 const data = this . lastWrite = Buffer . from ( buffer ) ; // copy
162+ if ( this . port . record ) {
163+ this . recording = Buffer . concat ( [ this . recording , data ] ) ;
164+ }
140165 if ( this . port . echo ) {
141166 process . nextTick ( ( ) => {
142167 if ( this . isOpen ) { this . emitData ( data ) }
143168 } ) ;
144169 }
145170 this . pendingWrite = null ;
171+ debug ( this . serialNumber , 'writing finished' ) ;
146172 } ) ;
147173 return this . pendingWrite ;
148174 }
149175
150176 update ( opt ) {
151177 return super . update ( opt )
178+ . then ( resolveNextTick )
152179 . then ( ( ) => {
153180 this . port . openOpt . baudRate = opt . baudRate ;
154181 } ) ;
155182 }
156183
157184 set ( opt ) {
158- return super . set ( opt ) ;
185+ return super . set ( opt ) . then ( resolveNextTick ) ;
159186 }
160187
161188 get ( ) {
162189 return super . get ( )
190+ . then ( resolveNextTick )
163191 . then ( ( ) => {
164192 return {
165193 cts : true ,
@@ -171,10 +199,10 @@ class MockBinding extends BaseBinding {
171199
172200 flush ( ) {
173201 return super . flush ( )
202+ . then ( resolveNextTick )
174203 . then ( ( ) => {
175204 this . port . data = Buffer . alloc ( 0 ) ;
176- } )
177- . then ( resolveNextTick ( ) ) ;
205+ } ) ;
178206 }
179207
180208 drain ( ) {
0 commit comments