Forum Discussion

BenoitB's avatar
BenoitB
Community Hero
4 years ago

Boolean or not ?

We have the need to set/get boolean value on components where sometimes property, or test data is not a boolean.

 

Please share and discuss about your best way to determine if a value is a boolean.

 

Mine is below.

 

 

/**
 * <a id="stringToBoolean"></a>
 * Renvoie le type boolean true ou false selon la chaîne en entrée :<br>
 * - "true", "yes", "on", "1", "oui", "vrai", "checked" renvoie true<br>
 * - "false", "no", "off", "0", "non", "faux", "unchecked", "", null renvoie false<br>
 * - autres valeurs, essaye de convertir en String pour l'évaluer, le cas échéant renvoie false
 * @function
 *  {string} [value=""] - Chaîne à convertir
 * @returns {boolean} Renvoie <b>true</b> ou <b>false</b>
 */
function stringToBoolean (value = "") {
  if (typeof value != 'string') {
    try {
      value = value.toString();
    }
    catch(e) {
     value = "";
    }
  }
  switch(value.toLowerCase().trim()){
    case "true" : 
    case "yes" : 
    case "on" :
    case "1" : 
    case "oui" :
    case "vrai" :
    case "checked" :
      return true;
    case "false" : 
    case "no" : 
    case "0" : 
    case "off" :
    case "" :
    case "non" :
    case "faux" :
    case "unchecked" :
    case null : 
      return false;
    default: 
      return Boolean(value);
  }
}

 

 

  • BenoitB's avatar
    BenoitB
    4 years ago

    Nice idea AlexKaras , but you can remove your aqString.ToLower as you compare in case-insensitve mode.

     

    So i make a simple benchmark with following code :

     

     

    function stringToBoolean (value = "") {
      if (typeof value != 'string') {
        try {
          value = value.toString();
        }
        catch(e) {
         value = "";
        }
      }
      switch(value.toLowerCase().trim()){
        case "true" : 
        case "yes" : 
        case "on" :
        case "1" : 
        case "oui" :
        case "vrai" :
        case "checked" :
          return true;
        case "false" : 
        case "no" : 
        case "-1" : 
        case "0" : 
        case "off" :
        case "" :
        case "non" :
        case "faux" :
        case "unchecked" :
        case null : 
          return false;
        default: 
          return Boolean(value);
      }
    }
    
    function TestBool(aValue) {
      Log.Message("Value = " + aValue);
      aqPerformance.Start("DefaultCounter", false);
      try { Log.Message("Alex = " + aqObject.CompareProperty(aqString.ToLower(aqConvert.VarToStr(aValue)), cmpMatches, "^(true)|(yes)|(t)|(y)|([1-9])$", false, lmNone)); } catch(e) { Log.Message("Alex, exception : " + e.message) };
      Log.Message("Perf Alex = " + aqPerformance.Value());
      aqPerformance.Start("DefaultCounter", false);
      try { Log.Message("Alex simple = " + aqObject.CompareProperty(aqConvert.VarToStr(aValue), cmpMatches, "^(true)|(yes)|(t)|(y)|([1-9])$", false, lmNone)); } catch(e) { Log.Message("Alex simple, exception : " + e.message) };
      Log.Message("Perf Alex simple = " + aqPerformance.Value());
      aqPerformance.Start("DefaultCounter", false);
      Log.Message("Bibi = " + stringToBoolean(aValue));
      Log.Message("Perf Bibi = " + aqPerformance.Value());
    }
    
    TestBool(true);
    TestBool(false);
    TestBool("true");
    TestBool("false");
    TestBool("yes");
    TestBool("no");
    TestBool(null);
    TestBool();
    TestBool(-1);
    TestBool(0);
    TestBool(1);
    TestBool(1.0);
    TestBool(NaN);
    TestBool({obj : 1});
    TestBool([1]);
    

     

     

    The result are :

    - on simple type, same results 😀

    - method with aqConvert is very slow 😆

    - on table/objetct type, different results, mine return "true", yours "false" 😔

     

    In conclusion i will stay with mine because of speed and less dependant of TestComplete.

    But i admit that your method is by concept a nice one !

     

    - detailled results below :

    Value = true
    Alex = true Perf = 13
    Alex2 = true Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = false
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = true
    Alex = true Perf Alex = 9
    Alex2 = true Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = false
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = yes
    Alex = true Perf Alex = 9
    Alex2 = true Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = no
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 7
    Value = null
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = undefined
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = -1
    Alex = false Perf Alex = 8
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = 0
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = false Perf Bibi = 2
    Value = 1
    Alex = true Perf Alex = 8
    Alex2 = true Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = 1
    Alex = true Perf Alex = 9
    Alex2 = true Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = NaN
    Alex = false Perf Alex = 9
    Alex2 = false Perf Alex2 = 7
    Bibi = true Perf Bibi = 2
    Value = [object Object]
    Alex = false Perf Alex = 11
    Alex2 = false Perf Alex2 = 9
    Bibi = true Perf Bibi = 2
    Value = 1
    Alex = true Perf Alex = 11
    Alex2 = true Perf Alex2 = 9
    Bibi = true Perf Bibi = 2

  • Hi Benoit,

     

    Your idea with performance measuring is really a great one. I thought about it after I wrote my initial reply to this thread but did not try it yet. 😞

     

    One more idea:

    Instead of

     

      switch(value.toLowerCase().trim()){
        case "true" : 
        case "yes" : 
        case "on" :
        case "1" : 
        case "oui" :
        case "vrai" :
        case "checked" :
          return true;
    

     

    which uses several 'case'-s without return (I understand the reason but I bet you know;) that this is not recommended technique), you may consider this:

     

    var strTrueList = 'true|yes|on|1|oui|vrai|checked';
    var strFalseList = 'false|no|off|0|non|faux|unchecked|'; // explicit null is not supported
    
    switch (true)
      case aqObject.CompareProperty(value.trim(), cmpIn, strTrueList, false, lmNone) :
        return true;
      case aqObject.CompareProperty(value.trim(), cmpIn, strFalseList, false, lmNone) :
        return false;
      default: 
        return Boolean(value);
    
    // or just
    var strTrueList = 'true|yes|on|1|oui|vrai|checked';
    if (aqObject.CompareProperty(value.trim(), cmpIn, strTrueList, false, lmNone))
      return true;
    else
      return false;
    

     

    (Though not sure if it is faster than native JScript code.)

     

    P.S.

    less dependant on TC objects

    My personal preference is opposite: if some TC object provides functionality that I need then I will use this object in favor of the native functionality provided by the scripting language that is used for the project.

    The reason for this is that it is much more easy to port the code that uses TC objects between projects based on different scripting languages.

    Sure, if one is an employee for the project that lasts for many years, the above might be irrelevant for him/her. But if one works, say, as a contractor/consultant, then the use of TC objects makes it faster and with less chance of an error to move generic/library test code between different projects.

     

    P.P.S.

    > - on table/objetct type, different results, mine return "true", yours "false" 😔

    I tried to evaluate

    Boolean({obj : 1})

    and

    Boolean({obj : 0})

    in TestComplete's Evaluate dialog. Result in both cases was True which makes me think that in your case True was returned not because obj property was set to 1, but because the whole argument for the Boolean() function was not null/empty and thus was evaluated to boolean True. (The same relates to the NaN argument.)

     

    • BenoitB's avatar
      BenoitB
      Community Hero

      Yes i was aware of that method but not answering my needs, perhaps i didn't explained them clearly.

       

      The main goal is to let user to use their standard definition of what is on or off, that could be a 0 and 1, or a true and false, or 'checked' and 'unchecked', or 'on' and 'off' , or '1' and null ...

       

      .. And moreover aqConvert is an heavy one ..

       

       

       

      • AlexKaras's avatar
        AlexKaras
        Champion Level 3

        Hi,

         

        I used practically the same but regex-based:

          return aqObject.CompareProperty(aqString.ToLower(aqConvert.VarToStr(aValue)), cmpMatches, "^(true)|(yes)|(t)|(y)|([1-9])$", false, lmNone);
        

         

  • jeanette17's avatar
    jeanette17
    New Contributor

    BenoitB wrote:

    We have the need to set/get boolean value on components where sometimes property, or test data is not a boolean.

     

    Please share and discuss about your best way to determine if a value is a boolean.

     

    Mine is below.

     

     

     

    /**
     * <a id="stringToBoolean"></a>
     * Renvoie le type boolean true ou false selon la chaîne en entrée :<br>
     * - "true", "yes", "on", "1", "oui", "vrai", "checked" renvoie true<br>
     * - "false", "no", "off", "0", "non", "faux", "unchecked", "", null renvoie false<br>
     * - autres valeurs, essaye de convertir en String pour l'évaluer, le cas échéant renvoie false
     * @function
     *  {string} [value=""] - Chaîne à convertir
     * @returns {boolean} Renvoie <b>true</b> ou <b>false</b>
     */
    function stringToBoolean (value = "") {
      if (typeof value != 'string') {
        try {
          value = value.toString();
        }
        catch(e) {
         value = "";
        }
      }
      switch(value.toLowerCase().trim()){
        case "true" : 
        case "yes" : 
        case "on" :
        case "1" : 
        case "oui" :
        case "vrai" :
        case "checked" :
          return true;
        case "false" : 
        case "no" : 
        case "0" : 
        case "off" :
        case "" :
        case "non" :
        case "faux" :
        case "unchecked" :
        case null : 
          return false;
        default: 
          return Boolean(value);
      }
    }

     

     

     


    Thanks for the support