Unit testing - how many test cases here - php

I have a method that takes an array as an argument, and returns true or false depending on the presence of a particular value.
In this scenario how many test cases should be written?
I think 3:
If the value is present
If the value is not present
If the array is empty (could be covered by 2 though?? )

I can think of 3 test cases:
If the array is not empty (or not null)
If the value is valid or not (I can pass an object where it expects a string :) )
If the value is present in array

It is the code of the function you want to test, so you cannot tell how many test cases are useful. Think again what your code does, how will the value be found?
An example: If your code tries to find a value with a certain name, and you make a string comparison, then think of the problems that can arise with string comparisons -> should the key be found case (in)sensitive, is null equal to an empty string, how does it handle duplicates and are other types converted correctly to strings (type juggling)?

Related

Why does "scalar" appear like this when I cast json_decode() (in non-associative mode) to an object?

While doing some code refactoring I momentarily ended up in a situation where I was basically doing the (somewhat abstracted-out) equivalent of
$data = (object)json_decode('"test"');
Of course I understand json_decode() generates objects on its own unless assoc is false. (Incidentally I got into this situation because I was in the middle of moving some format processing code around, and I hadn't yet realized one of my (object) casts was now redundant.)
But... when this happened, PHP decided that $data contained:
stdClass Object
(
[scalar] => test
)
Wat.
scalar?!
Last I learned, "test" is a string, so it seems more than one pile of things has fallen over internally here. Or is this unintuitive yet intended design?!
I have of course removed the (object) and things work exactly how I intended now. So there's no bug here per se. I just wanted to understand what just happened.
Here you go, in case you want to join in the headscratching:
php -r 'print_r((object)json_decode("\"test\""));'
I'm using 7.0.25.
This is exactly what the manual specifies will happen when casting a scalar type (i.e. int, string, float, boolean) to an object.
If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. An array converts to an object with properties named by keys and corresponding values. Note that in this case before PHP 7.2.0 numeric keys have been inaccessible unless iterated.
For any other value, a member variable named scalar will contain the value.
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'

Accessing specified Element of Array with Twig

I have the following array and i want to access the value of a specified element with twig.
numbers => Array ([01234567] => Array ( [0] => 9876543210 [1] => 8765432109 [2] => 0000000000))
I know there is only one entry in numbers, so I want to access the array with the key 01234567 directly.
Even tough numbers|keys[0] does return the correct key, I can't use it like numbers[numbers|keys[0]] to get the array. I also tried the attribute(array, item) function, but i didn't got it to work.
Is it possible to access it directly or do I need to use loops?
You have found a probably undocumented "feature" of Twig. If you check the source code, twig tries to determine if the given key is numeric, or not. It does this check with the ctype_digit function, which checks if a variable contains only numeric characters.
The example in your question contains an array key, which meets this conditions: it contains only numbers. Unfortunately, it also starts with a zero, which is removed when the string is converted into an integer.
I'm not exactly sure that this is intended behavior, so you may try to report this example as a bug.
For the current twig implementation, because everything except the loop construct uses the getAttribute function, you have no other choice but to use a for loop.

php associative array values always set?

$test['test'] = 'test';
if(isset($test['test']['x']))
return $test['test']['x'];
This statement returns the first character of the string in $test['test'] (in this case 't'), no matter what is specified as dimension 2.
I can't wrap my head around this behavior. I use isset() all the time. Please advise.
This happens because you're not indexing an array, you're indexing a string. Strings are not arrays in PHP. They happen to share a concept of indexes with arrays, but are really character sequences even though there is no distinct char data type in PHP.
In this case, since strings are only indexed numerically, 'x' is being converted into an integer, which results in 0. So PHP is looking for $test['test'][0]. Additionally $test is only a single-dimensional array, assuming 'test' is the only key inside.
Not really relevant to your question, but if you try something like this you should get 'e', because when converting '1x' to an integer, PHP drops anything that isn't a digit and everything after it:
// This actually returns $test['test'][1]
return $test['test']['1x'];
If you're looking for a second dimension of the $test array, $test['test'] itself needs to be an array. This will work as expected:
$test['test'] = array('x' => 'test');
if (isset($test['test']['x']))
return $test['test']['x'];
Of course, if your array potentially contains NULL values, or you want to make sure you're checking an array, use array_key_exists() instead of isset() as sirlancelot suggests. It's sliiiiightly slower, but doesn't trip on NULL values or other indexable types such as strings and objects.
Use array_key_exists for testing array keys.
It's returning 't' because all strings can be treated as arrays and 'x' will evaluate to 0 which is the first letter/value in the variable.

Unify variable types of array elements

After hours of debugging, I found an error in one of my scripts. For saving different event types in a database, I have an array of unique data for each event that can be used to identify the event.
So I basically have some code like
$key = md5(json_encode($data));
to generate a unique key for each event.
Now, in some cases, a value in the $data array is an integer, sometimes a string (depending on where it comes from - database or URL). That causes the outputs of json_encode() to be different from each other, though - once including quotes, once not.
Does anybody know a way to "unify" the variable types in the $data array? That would probably mean converting all strings that only contain an integer value to integer. Anything else I have to take care of when using json_encode()?
array_walk_recursive combined with a function you have written to the effect of maybe_intval which performs the conversion you talk about on a single element.
EDIT: having read the documentation for array_walk_recursive more closely you'll actually want to write your own recursive function
function to_json($obj){
if(is_object($obj))
$obj=(array)$obj;
if(is_array($obj))
return array_map('to_json',$obj);
return "$obj"; // or return is_int($obj)?intval($obj):$obj;
}

How to check if an array has an element at the specified index?

I know there is array_key_exists() but after reading the documentation I'm not really sure if it fits for this case:
I have an $array and an $index. Now I want to access the $array, but don't know if it has an index matching $index. I'm not talking about an associative array, but an plain boring normal numerically indexed array.
Is there an safe way to figure out if I would really access an $array element with the given $index (which is an integer!)?
PHP may not care if I access an array with an index out of bounds and maybe just returns NULL or so, but I don't want to even attempt to code dirty, so I want to check if the array has the key, or not ;-)
You can use either the language construct isset, or the function array_key_exists : numeric or string key doesn't matter : it's still an associative array, for PHP.
isset should be a bit faster (as it's not a function), but will return false if the element exists and has the value NULL.
For example, considering this array :
$a = array(
123 => 'glop',
456 => null,
);
And those three tests, relying on isset :
var_dump(isset($a[123]));
var_dump(isset($a[456]));
var_dump(isset($a[789]));
You'll get this kind of output :
boolean true
boolean false
boolean false
Because :
in the first case, the element exists, and is not null
in the second, the element exists, but is null
and, in the third, the element doesn't exist
On the other hand, using array_key_exists like in this portion of code :
var_dump(array_key_exists(123, $a));
var_dump(array_key_exists(456, $a));
var_dump(array_key_exists(789, $a));
You'll get this output :
boolean true
boolean true
boolean false
Because :
in the two first cases, the element exists -- even if it's null in the second case
and, in the third, it doesn't exist.
You can easily use isset():
if (isset($array[$index])) {
// array index $index exists
}
And as you have suggested, PHP is not very kind if you try to access a non-existent index, so it is crucial that you check that you are within bounds when dealing with accessing specific array indexes.
If you decide to use array_key_exists(), please note that there is a subtle difference:
isset() does not return TRUE for array
keys that correspond to a NULL value,
while array_key_exists() does.
That's exactly what the array_key_exists is for. It works on both numerical and string indexes.

Categories