| module Misc_Helpers { |
| |
| import from Native_Functions all; |
| import from TCCConversion_Functions all; |
| |
| modulepar { |
| charstring mp_osmo_repo := "nightly"; |
| } |
| |
| /* Test the Osmocom repository (nightly, latest, 2021q4, ...), from which the |
| * SUT is running (OS#4878). Usage examples: |
| * if (Misc_Helpers.f_osmo_repo_is("nightly")) { |
| * ... |
| * } |
| * if (Misc_Helpers.f_osmo_repo_is(("nightly", "2021q4"))) { |
| * ... |
| * } |
| */ |
| function f_osmo_repo_is(template charstring ver) return boolean { |
| return match(mp_osmo_repo, ver); |
| } |
| |
| /* Try to properly shutdown a testcase. |
| * The reliable method to stop a testcase without running into dynamic |
| * testcase errors due to unconnected ports receiving messages is to call |
| * all component.stop before terminating. However, this can only be called |
| * from the mtc! So in case we want to terminate from a component that is not |
| * the mtc we try to do the next best thing which is calling mtc.stop and |
| * hoping for the best. |
| */ |
| function f_shutdown(charstring file, integer line, verdicttype verdict := none, |
| charstring text := "") { |
| if (verdict != none) { |
| text := file & ":" & int2str(line) & " : " & text |
| setverdict(verdict, text); |
| } |
| |
| log("Stopping testcase execution from ", file, ":", line) |
| if (self == mtc) { |
| /* Properly stop all ports before disconnecting them. This avoids |
| * running into the dynamic testcase error due to messages arriving on |
| * unconnected ports. */ |
| all component.stop; |
| } |
| mtc.stop |
| } |
| |
| function f_addr_is_ipv6(charstring addr) return boolean { |
| for (var integer i := 0; i < lengthof(addr); i := i + 1) { |
| if (addr[i] == ":") { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| function f_addrstr2addr(charstring addr) return octetstring { |
| if (f_addr_is_ipv6(addr)) { |
| return f_inet6_addr(addr); |
| } else { |
| return f_inet_addr(addr); |
| } |
| } |
| |
| /* Return a count of how many times sub_str occurs in str. */ |
| function f_strstr_count(in charstring str, in charstring sub_str) return integer |
| { |
| var integer count := 0; |
| var integer pos := 0; |
| |
| while (true) { |
| var integer at := f_strstr(str, sub_str, pos); |
| if (at < 0) { |
| break; |
| } |
| count := count + 1; |
| pos := at + 1; |
| } |
| return count; |
| } |
| |
| /* Return true if str ends exactly with token: */ |
| function f_str_endswith(charstring str, charstring token) return boolean |
| { |
| if (lengthof(str) < lengthof(token)) { |
| return false; |
| } |
| var charstring str_end := substr(str, lengthof(str) - lengthof(token), lengthof(token)); |
| return str_end == token; |
| } |
| |
| /* Replace all matches of token "find" with "repl" in "str" */ |
| function f_str_replace(charstring str, charstring find, charstring repl) return charstring |
| { |
| var integer pos := f_strstr(str, find, 0); |
| if (pos < 0) { |
| return str; |
| } |
| var charstring prefix := substr(str, 0, pos); |
| var integer suffix_pos := pos + lengthof(find); |
| var charstring suffix := substr(str, suffix_pos, lengthof(str) - suffix_pos); |
| |
| var charstring new_str := prefix & repl & f_str_replace(suffix, find, repl); |
| return new_str; |
| } |
| |
| type record of charstring ro_charstring; |
| function f_str_split(charstring str, charstring delim := "\n") return ro_charstring |
| { |
| var integer pos := 0; |
| var ro_charstring parts := {}; |
| var integer delim_pos; |
| var integer end := lengthof(str); |
| while (pos < end) { |
| delim_pos := f_strstr(str, delim, pos); |
| if (delim_pos < 0) { |
| delim_pos := end; |
| } |
| if (delim_pos > pos) { |
| parts := parts & { substr(str, pos, delim_pos - pos) }; |
| } |
| pos := delim_pos + lengthof(delim); |
| } |
| return parts; |
| } |
| |
| } |