Skip to content

Commit 17d0e3e

Browse files
committed
fixes Add null checks for JSON stream #154
Changes made: * Change over to SWITCH statement in `streamTokens` method to improve readability * Added token `VALUE_NULL` to deal with issue where object may have a field explicitly set to NULL as described in Issue Add null checks for JSON stream #154 * Added additional test to check for object with field explicitly set to NULL
1 parent 56973f7 commit 17d0e3e

File tree

2 files changed

+100
-34
lines changed

2 files changed

+100
-34
lines changed

sfdx-source/apex-mocks/main/classes/fflib_ApexMocksUtils.cls

+31-27
Original file line numberDiff line numberDiff line change
@@ -189,39 +189,43 @@ public class fflib_ApexMocksUtils
189189
private static void streamTokens(JSONParser fromStream, JSONGenerator toStream, JSONParserEvents events)
190190
{
191191
Integer depth = 0;
192-
while (fromStream.nextToken()!=null)
192+
while (fromStream.nextToken() != null)
193193
{
194194
// Give event handler chance to inject
195-
if(events!=null)
195+
if (events != null) {
196196
events.nextToken(fromStream, depth, toStream);
197-
// Forward to output stream
198-
JSONToken currentToken = fromStream.getCurrentToken();
199-
if(currentToken == JSONToken.START_ARRAY) {
200-
toStream.writeStartArray();
201-
depth++;
202-
}
203-
else if(currentToken == JSONToken.START_OBJECT) {
204-
toStream.writeStartObject();
205-
depth++;
206197
}
207-
else if(currentToken == JSONToken.FIELD_NAME)
208-
toStream.writeFieldName(fromStream.getCurrentName());
209-
else if(currentToken == JSONToken.VALUE_STRING ||
210-
currentToken == JSONToken.VALUE_FALSE ||
211-
currentToken == JSONToken.VALUE_TRUE ||
212-
currentToken == JSONToken.VALUE_NUMBER_FLOAT ||
213-
currentToken == JSONToken.VALUE_NUMBER_INT)
214-
toStream.writeString(fromStream.getText());
215-
else if(currentToken == JSONToken.END_OBJECT) {
216-
toStream.writeEndObject();
217-
depth--;
218-
}
219-
else if(currentToken == JSONToken.END_ARRAY) {
220-
toStream.writeEndArray();
221-
depth--;
198+
199+
// Forward to output stream
200+
switch on fromStream.getCurrentToken() {
201+
when START_ARRAY {
202+
toStream.writeStartArray();
203+
depth++;
204+
}
205+
when START_OBJECT {
206+
toStream.writeStartObject();
207+
depth++;
208+
}
209+
when FIELD_NAME {
210+
toStream.writeFieldName(fromStream.getCurrentName());
211+
}
212+
when VALUE_STRING, VALUE_FALSE, VALUE_TRUE, VALUE_NUMBER_FLOAT, VALUE_NUMBER_INT {
213+
toStream.writeString(fromStream.getText());
214+
}
215+
when VALUE_NULL {
216+
toStream.writeNull();
217+
}
218+
when END_OBJECT {
219+
toStream.writeEndObject();
220+
depth--;
221+
}
222+
when END_ARRAY {
223+
toStream.writeEndArray();
224+
depth--;
225+
}
222226
}
223227
// Don't continue to stream beyond the initial starting point
224-
if(depth==0)
228+
if (depth == 0)
225229
break;
226230
}
227231
}

sfdx-source/apex-mocks/test/classes/fflib_ApexMocksUtilsTest.cls

+69-7
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ public class fflib_ApexMocksUtilsTest
8585
}
8686

8787
@isTest
88-
private static void makeRelationship_GenericOverload_ReturnsObjectsWithRelationFieldSet() {
88+
private static void makeRelationship_GenericOverload_ReturnsObjectsWithRelationFieldSet()
89+
{
8990
//Given
9091
SObject acc = Schema.getGlobalDescribe().get('Account').newSObject();
9192
acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType()));
@@ -128,8 +129,8 @@ public class fflib_ApexMocksUtilsTest
128129
}
129130

130131
@isTest
131-
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidParentType() {
132-
132+
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidParentType()
133+
{
133134
// Setup parent object
134135
SObject acc = Schema.getGlobalDescribe().get('Account').newSObject();
135136
acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType()));
@@ -155,8 +156,8 @@ public class fflib_ApexMocksUtilsTest
155156
}
156157

157158
@isTest
158-
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidChildType() {
159-
159+
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidChildType()
160+
{
160161
// Setup parent object
161162
SObject acc = Schema.getGlobalDescribe().get('Account').newSObject();
162163
acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType()));
@@ -182,8 +183,8 @@ public class fflib_ApexMocksUtilsTest
182183
}
183184

184185
@isTest
185-
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidFieldName() {
186-
186+
private static void makeRelationship_GenericOverload_ThrowsErrorOnInvalidFieldName()
187+
{
187188
// Setup parent object
188189
SObject acc = Schema.getGlobalDescribe().get('Account').newSObject();
189190
acc.put('Id', fflib_IDGenerator.generate(acc.getSObjectType()));
@@ -208,6 +209,67 @@ public class fflib_ApexMocksUtilsTest
208209
System.Assert.areEqual('SObject field not found: MyInvalidField', errorMessage);
209210
}
210211

212+
@IsTest
213+
private static void makeRelationship_ObjectWithNull_DoesNotThrowErrorOnJSONExceptionCanNotWriteAFieldNameExpectingAValue()
214+
{
215+
// Given
216+
Product2 prod1 = new Product2(
217+
Id = fflib_IDGenerator.generate(Product2.SObjectType),
218+
Name = 'Product1',
219+
ProductCode = 'P1',
220+
Description = null,
221+
StockKeepingUnit = 'P1'
222+
);
223+
224+
Product2 prod2 = new Product2(
225+
Id = fflib_IDGenerator.generate(Product2.SObjectType),
226+
Name = 'Product2',
227+
ProductCode = 'P2',
228+
Description = 'this is another product',
229+
StockKeepingUnit = 'P2'
230+
);
231+
232+
OrderItem oi1 = new OrderItem(
233+
Id = fflib_IDGenerator.generate(OrderItem.SObjectType),
234+
Product2Id = prod1.Id,
235+
Product2 = prod1,
236+
UnitPrice = 10,
237+
Quantity = 1
238+
);
239+
240+
OrderItem oi2 = new OrderItem(
241+
Id = fflib_IDGenerator.generate(OrderItem.SObjectType),
242+
Product2Id = prod2.Id,
243+
Product2 = prod2,
244+
UnitPrice = 10,
245+
Quantity = 1
246+
);
247+
248+
Order order = new Order();
249+
250+
Exception exceptionThatWasCalled = null;
251+
252+
// When
253+
Test.startTest();
254+
255+
try {
256+
fflib_ApexMocksUtils.makeRelationship(
257+
List<Order>.class,
258+
new List<Order>{ order },
259+
OrderItem.OrderId,
260+
new List<List<OrderItem>>{ new List<OrderItem>{oi1, oi2} }
261+
);
262+
} catch (JSONException e) {
263+
exceptionThatWasCalled = e;
264+
}
265+
266+
Test.stopTest();
267+
268+
// Then
269+
System.debug(exceptionThatWasCalled);
270+
Assert.isNull(exceptionThatWasCalled, 'Exception should not have been called');
271+
}
272+
211273
@isTest
212274
static void setReadOnlyFields_CreatedByIdSetToCurrentUserId_IdFieldSetSuccessfully() {
213275

0 commit comments

Comments
 (0)