@@ -19,6 +19,7 @@ import { toMessage } from './firestore-to-proto';
1919import { Constructor } from 'protobufjs' ;
2020
2121const {
22+ AuditInfo,
2223 Coordinates,
2324 Job,
2425 LinearRing,
@@ -28,6 +29,7 @@ const {
2829 Task,
2930 LocationOfInterest,
3031} = GroundProtos . ground . v1beta1 ;
32+ const { Timestamp } = GroundProtos . google . protobuf ;
3133
3234describe ( 'toMessage()' , ( ) => {
3335 [
@@ -138,6 +140,13 @@ describe('toMessage()', () => {
138140 } ,
139141 expected : new Survey ( ) ,
140142 } ,
143+ {
144+ desc : 'skips repeated field when value is not an array' ,
145+ input : {
146+ '1' : 'not an array' ,
147+ } ,
148+ expected : new LinearRing ( ) ,
149+ } ,
141150 {
142151 desc : 'converts enum value' ,
143152 input : {
@@ -152,6 +161,45 @@ describe('toMessage()', () => {
152161 input : { } ,
153162 expected : new Task . DateTimeQuestion ( ) ,
154163 } ,
164+ {
165+ desc : 'skips non-numeric enum value' ,
166+ input : {
167+ '1' : 'not-a-number' ,
168+ } ,
169+ expected : new Task . DateTimeQuestion ( ) ,
170+ } ,
171+ {
172+ desc : 'converts google.protobuf.Timestamp field' ,
173+ input : {
174+ '1' : 'user-123' ,
175+ '2' : { '1' : 1700000000 , '2' : 500 } ,
176+ } ,
177+ expected : new AuditInfo ( {
178+ userId : 'user-123' ,
179+ clientTimestamp : new Timestamp ( { seconds : 1700000000 , nanos : 500 } ) ,
180+ } ) ,
181+ } ,
182+ {
183+ desc : 'skips non-numeric keys' ,
184+ input : {
185+ '2' : 'Survey name' ,
186+ notANumber : 'should be ignored' ,
187+ foo : 42 ,
188+ } ,
189+ expected : new Survey ( {
190+ name : 'Survey name' ,
191+ } ) ,
192+ } ,
193+ {
194+ desc : 'skips unrecognized field numbers' ,
195+ input : {
196+ '2' : 'Survey name' ,
197+ '999' : 'unknown field should be ignored' ,
198+ } ,
199+ expected : new Survey ( {
200+ name : 'Survey name' ,
201+ } ) ,
202+ } ,
155203 {
156204 desc : 'converts repeated message' ,
157205 input : {
@@ -171,8 +219,42 @@ describe('toMessage()', () => {
171219 } ,
172220 ] . forEach ( ( { desc, input, expected } ) =>
173221 it ( desc , ( ) => {
174- const output = toMessage ( input , expected . constructor as Constructor < any > ) ;
222+ const output = toMessage (
223+ input ,
224+ expected . constructor as Constructor < unknown >
225+ ) ;
175226 expect ( output ) . toEqual ( expected ) ;
176227 } )
177228 ) ;
229+
230+ it ( 'logs and skips fields whose conversion returns an Error' , ( ) => {
231+ const debugSpy = spyOn ( console , 'debug' ) ;
232+ const output = toMessage (
233+ {
234+ '2' : 'Survey name' ,
235+ '4' : 'not an object' , // acl map expects object → Error
236+ } ,
237+ Survey
238+ ) ;
239+ expect ( output ) . toEqual ( new Survey ( { name : 'Survey name' } ) ) ;
240+ expect ( debugSpy ) . toHaveBeenCalledWith ( jasmine . any ( Error ) ) ;
241+ } ) ;
242+
243+ it ( 'returns Error when constructor is not a protojs message' , ( ) => {
244+ class NotAProtoMessage { }
245+ const output = toMessage ( { } , NotAProtoMessage as Constructor < unknown > ) ;
246+ expect ( output ) . toEqual ( jasmine . any ( Error ) ) ;
247+ expect ( ( output as Error ) . message ) . toContain ( 'is not a protojs message' ) ;
248+ } ) ;
249+
250+ it ( 'returns Error when message type not found in registry' , ( ) => {
251+ class UnknownProtoMessage {
252+ static getTypeUrl ( ) : string {
253+ return '/ground.v1beta1.DoesNotExist' ;
254+ }
255+ }
256+ const output = toMessage ( { } , UnknownProtoMessage as Constructor < unknown > ) ;
257+ expect ( output ) . toEqual ( jasmine . any ( Error ) ) ;
258+ expect ( ( output as Error ) . message ) . toContain ( 'not found in registry' ) ;
259+ } ) ;
178260} ) ;
0 commit comments