function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
marko.tomicmarko.tomic 

runAs() acts inconsistently and wrong.. or I am wrong?

Hi to all,

 

I have this test method:

 

public static testmethod void testMe(){

    Profile p = [select id from profile where name='Standard User'];
      String randomName = string.valueof(Datetime.now()).replace('-','').replace(':','').replace(' ','');
       User u = new User(alias = 'standt', email=randomName + 'standarduser@testorg.com',
      emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US',
      localesidkey='en_US', profileid = p.Id,
      timezonesidkey='America/Los_Angeles', username=randomName + 'standarduser@testorg.com');
      insert u;
    
     System.runAs(u) {
        System.debug('************');
        System.debug(UserInfo.getLocale());
        String s = '6,663.33';
        Decimal de = Decimal.valueOf(s);
        System.debug(String.valueOf(de));
      }

 

 

Problem:


This line of code fails even if the number is perfectly valid for specified local:

String s = '6,663.33';
Decimal de = Decimal.valueOf(s);

 

System.TypeException: Invalid decimal: 6,663.33

 

Why this breaks?

 

I tried to create an custom object with one field of type currency and with logged in user whose local is de_DE system failed while saving 6,663.33 but after I changed local to US it succeeded  just like I expected. Why it doesn't work like that in test methods also?

 

Thank you very much in advance!

 

Best Answer chosen by Admin (Salesforce Developers) 
Starz26Starz26

the locale is only valid when converting numbers to strings.

 

The decimal.valueOf() cannot handle anything but the decimal point as far as I know.

 

You will have to create methods to parse the strings based on local if using more than two decimal places.

 

If just using currency with two decimal places you can use a method similar to this to change to just the decimal seperator at the dollars and cents:

 



public decimal stringToDecimal(String a){
//instantiate new Pattern object        
        Pattern p = Pattern.compile('[^0-9]');
       
a = p.matcher(a).replaceAll('');
return decimal.valueOf(a.substring(0,a.length()-2) + '.' + a.substring(a.length()-2));
}

All Answers

Starz26Starz26

removing the comma solves the error.

marko.tomicmarko.tomic

@Starz26

 

Thank you for your answer but I'm not sure that I understood correctly. If by "comma" you mean separator for thousand in the number than I don't understand how that can be a solution because user from USA will enter a number with comma for sure since it is a valid thousand separator. Changing the local setting on the current user to US should make that system expects comma for thousand separator. Or maybe I am wrong?

Starz26Starz26

the , is not valid in decimal.ValueOf you need to have numeric only

 

Just use

 

string.replaceAll(',','');

 

When using decimal.valueOf of a string with a , in it, you get the error as you stated, when doing the same thing after removing the , the code runs fine.

 

 

marko.tomicmarko.tomic

Changing the totally valid user's input is not an option, not a chance. Decimal.valueOf method should be able to cenvert different user's input successfully. In the database, it will be always stored as 6663.33 but user in USA will enter it as 6,663.33, in Germany 6.663,33 and in some other part of the world 6 663,33. So, in different contexts(User's locale settings?) Decimal.valueOf must handle different inputs and I should be able to simulate that in the tests. Right?

Starz26Starz26

the locale is only valid when converting numbers to strings.

 

The decimal.valueOf() cannot handle anything but the decimal point as far as I know.

 

You will have to create methods to parse the strings based on local if using more than two decimal places.

 

If just using currency with two decimal places you can use a method similar to this to change to just the decimal seperator at the dollars and cents:

 



public decimal stringToDecimal(String a){
//instantiate new Pattern object        
        Pattern p = Pattern.compile('[^0-9]');
       
a = p.matcher(a).replaceAll('');
return decimal.valueOf(a.substring(0,a.length()-2) + '.' + a.substring(a.length()-2));
}

This was selected as the best answer
marko.tomicmarko.tomic

Ok, this proposal I can accept as a solution. Tnx.

 

What made me think that there is already locale support for string to decimal conversion is that in Salesforce it is enough just to change the locale setting in the user from de_DE to en_US and currency field in the custom object will start to  understand numbers with commas, for example in this case 6,663.33. Still I don't understand how it works there.