With random generation, most of the fields are due to be quite well covered. If the field is of a type with a wide space, e.g. address is of 32 bits, then most likely not each and every of the 0xffffffff values will be generated. As verification engineers, we know that bugs tend to hide in the edges. That is - what will happen if the transfer is sent to the last address, to 0xffffffff? The verification environment challenge is, guaranteeing that these edge cases will be covered.
Making sure that edge cases are generated is easily achieved with the "select edges". For example:
extend transfer {
// For ~half of the transfers, the address will be
// 0 or 0xffffffff
keep soft address == select {
50 : edges;
50 : others;
};
};
This "select edges" is an old feature. What I want to show here is a small utility answering the question of "should I go now and define this "select edge" on all fields?" This seems to be a very exhausting task ....
For this, I suggest using the e reflection to locate fields of interest. For example, all fields whose range is larger than 0xffffff.
This piece of code searches for fields defined in a given package with range larger than the given parameter, num_of_vals -
var t : rf_type;
for each rf_struct in rf_manager.get_user_types() {
for each (f) in it.get_declared_fields() {
// Do not add constraints to fields that
// - are not generate-able
// - were defined in a package other than what was requested
if f.is_ungenerated() or
f.get_declaration_module().get_package().get_name() != package_name {
continue;
};
t = f.get_type();
if t is a rf_numeric (nu) {
if ipow(2, nu.get_size_in_bits()) > num_of_vals {
fields.add( f);
};
};
}; // for each field
Once you have the list of fields of interest, you can do many things with it. For example, write into a file code similar to the"select edge" code shown above:
write_code (s : rf_struct, fs : list of rf_field) is {
var my_file := files.open("cover_edges.e", "rw","big fields");
files.write(my_file, append("extend",s.get_name(),"{"));
for each in fs {
files.write(my_file,
append(" // Field defined in ",
it.get_declaration_module().get_name(),
" @line ",
it.get_declaration_source_line_num()));
files.write(my_file,
append(" // Field type is ",
it.get_type().get_name()));
files.write(my_file,
append(" keep soft ", it.get_name(),
" == select {"));
files.write(my_file, " 50 : edges;");
files.write(my_file, " 50 : others;");
files.write(my_file, " };");
};
files.write(my_file, "};");
files.close(my_file);
};
You could copy and modify the code above, using the reflection to find fields by many more criteria, e.g. all fields that have "address" in their names, all fields of specific types, anything your imagination might come up with...
If you have any questions, or, even better, any suggestions for cool extensions of this example, please do share.
Efrat Shneydor