///|
/// Check if haystack contains needle substring.
fn contains(haystack : String, needle : String) -> Bool {
let h_len = haystack.length()
let n_len = needle.length()
if n_len == 0 {
return true
}
if n_len > h_len {
return false
}
for i = 0; i <= h_len - n_len; i = i + 1 {
let mut found = true
for j = 0; j < n_len; j = j + 1 {
if haystack[i + j] != needle[j] {
found = false
break
}
}
if found {
return true
}
}
false
}
///|
/// Strip trailing spaces from a string.
fn strip_trailing_space(s : String) -> String {
let len = s.length()
let mut end = len
while end > 0 && s[end - 1] == ' ' {
end = end - 1
}
if end == len {
return s
}
let buf = StringBuilder::new()
for i = 0; i < end; i = i + 1 {
buf.write_char(s[i].to_int().unsafe_to_char())
}
buf.to_string()
}
///|
/// Generate a code snippet for implementing an undefined step.
///
/// Detects potential cucumber expression parameters in the step text:
/// integers become {int}, quoted strings become {string}, decimals become {float}.
fn generate_snippet(step_text : String, keyword : String) -> String {
let method = match keyword {
"Given " => "given"
"When " => "when"
"Then " => "then"
_ => "step"
}
let pattern = infer_pattern(step_text)
let kw = strip_trailing_space(keyword)
let buf = StringBuilder::new()
buf.write_string("s.")
buf.write_string(method)
buf.write_string("(\"")
buf.write_string(pattern)
buf.write_string("\", fn(ctx) raise {\n")
buf.write_string(" raise PendingStep(step=\"")
buf.write_string(pattern)
buf.write_string("\", keyword=\"")
buf.write_string(kw)
buf.write_string("\", message=\"TODO: implement step\")\n")
buf.write_string("})")
buf.to_string()
}
///|
/// Infer cucumber expression pattern from concrete step text.
/// Replaces integers with {int}, quoted strings with {string}, decimals with {float}.
fn infer_pattern(text : String) -> String {
let buf = StringBuilder::new()
let len = text.length()
let mut i = 0
while i < len {
let ch = text[i]
// Detect quoted strings: "..."
if ch == '"' {
let mut j = i + 1
while j < len && text[j] != '"' {
j = j + 1
}
if j < len {
buf.write_string("{string}")
i = j + 1
continue
}
}
// Detect numbers: sequences of digits, optionally with decimal point
if ch >= '0' && ch <= '9' {
let mut j = i
let mut has_dot = false
while j < len &&
(
(text[j] >= '0' && text[j] <= '9') ||
(text[j] == '.' && not(has_dot))
) {
if text[j] == '.' {
has_dot = true
}
j = j + 1
}
if has_dot {
buf.write_string("{float}")
} else {
buf.write_string("{int}")
}
i = j
continue
}
buf.write_char(ch.to_int().unsafe_to_char())
i = i + 1
}
buf.to_string()
}