Skip to content

Commit

Permalink
Tests support control chars widths 0 or 1 (gyscos#789)
Browse files Browse the repository at this point in the history
* fix 'cargo test' with unicode-width 0.1.12

which would fail like this:

test utils::lines::spans::tests::test_control_chars_have_width_1 ... FAILED

failures:

---- utils::lines::spans::tests::test_control_chars_have_width_1 stdout ----
thread 'utils::lines::spans::tests::test_control_chars_have_width_1' panicked at /home/user/1tmp/ncurses_things/cursive/cursive-core/src/utils/lines/spans/tests.rs:55:9:
assertion `left == right` failed: Width of control character \u{0000} is not 1
  left: 0
 right: 1
stack backtrace:
   0: rust_begin_unwind
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
   2: core::panicking::assert_failed_inner
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:337:23
   3: core::panicking::assert_failed
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:297:5
   4: cursive_core::utils::lines::spans::tests::test_control_chars_have_width_1
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/macros/mod.rs:58:21
   5: cursive_core::utils::lines::spans::tests::test_control_chars_have_width_1::{{closure}}
             at ./src/utils/lines/spans/tests.rs:32:37
   6: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

failures:
    utils::lines::spans::tests::test_control_chars_have_width_1

test result: FAILED. 29 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s

* fix cargo test --example select_test

... to work with unicode-width 0.1.12 as well.

before this, because it was expecting only 0.1.13,
it was failing with the following output:

     Running unittests examples/select_test.rs (target/x86_64-unknown-linux-gnu/debug/examples/select_test-d45f2e1e4022a737)

running 4 tests
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0                                                                                |
1                                                                                |
2                           ┌┤ Where are you from? ├┐                            |
3                           │      Abidjan       ▒  │                            |
4                           │     Abu Dhabi      |  │                            |
5                           │       Abuja        |  │                            |
6                           │       Accra        |  │                            |
7                           │     Adamstown      |  │                            |
8                           │    Addis Ababa     |  │                            |
9                           │      Algiers       |  │                            |
0                           │       Alofi        |  │                            |
1                           │       Amman        |  │                            |
2                           │     Amsterdam      |  │                            |
3                           └───────────────────────┘                            |
4                                                                                |
5                                                                                |
x--------------------------------------------------------------------------------x

test tests::displays ... ok
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0                                                                                |
1                                                                                |
2                           ┌┤ Where are you from? ├┐                            |
3                           │   short nul 1str   |  │                            |
4                           │       1thru8       |  │                            |
5                           │   tabandnewline    |  │                            |
6                           │      bthru15       |  │                            |
7                           │      16thru1F      |  │                            |
8                           │       7Fonly       |  │                            |
9                           │      80thru89      |  │                            |
0                           │      8Athru93      |  │                            |
1                           │      94thru9D      |  │                            |
2                           │      9Ethru9F      ▒  │                            |
3                           └───────────────────────┘                            |
4                                                                                |
5                                                                                |
x--------------------------------------------------------------------------------x

captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0                                                                                |
1                                                                                |
2                           ┌┤ Where are you from? ├┐                            |
3                           │   short nul 1str   |  │                            |
4                           │       1thru8       |  │                            |
5                           │   tabandnewline    |  │                            |
6                           │      bthru15       |  │                            |
7                           │      16thru1F      |  │                            |
8                           │       7Fonly       |  │                            |
9                           │      80thru89      |  │                            |
0                           │      8Athru93      |  │                            |
1                           │      94thru9D      |  │                            |
2                           │      9Ethru9F      ▒  │                            |
3                           └───────────────────────┘                            |
4                                                                                |
5                                                                                |
x--------------------------------------------------------------------------------x
thread '
tests::control_chars_become_replacement_char' panicked at cursive/examples/select_test.rs:148:9:
assertion `left == right` failed: tabs and newline should've been replaced with replacement char � aka \u{FFFD}
  left: 0
 right: 1
stack backtrace:
thread 'tests::nuls_become_replacement_char' panicked at cursive/examples/select_test.rs:133:9:
assertion `left == right` failed: nuls aka \0 in strings are supposed to become the replacement char '�'
  left: 0
 right: 1
captured piece:
x01234567890123456789012345678901234567890123456789012345678901234567890123456789x
0                                                                                |
1                                                                                |
2                                                                                |
3                                                                                |
4                                                                                |
5                         ┌────────────────────────────┐                         |
6                         │ Abu Dhabi is a great city! │                         |
7                         │                            │                         |
8                         │                     <Quit> │                         |
9                         └────────────────────────────┘                         |
0                                                                                |
1                                                                                |
2                                                                                |
3                                                                                |
4                                                                                |
5                                                                                |
x--------------------------------------------------------------------------------x

test tests::interacts ... ok
   0: rust_begin_unwind
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_fmt
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:72:14
   2: core::panicking::assert_failed_inner
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:403:23
   3: core::panicking::assert_failed
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:363:5
   4: select_test::tests::control_chars_become_replacement_char
             at ./examples/select_test.rs:148:9
   5: select_test::tests::control_chars_become_replacement_char::{{closure}}
             at ./examples/select_test.rs:142:47
   6: core::ops::function::FnOnce::call_once
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/ops/function.rs:250:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: rust_begin_unwind
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_fmt
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:72:14
   2: core::panicking::assert_failed_inner
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:403:23
   3: core::panicking::assert_failed
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/panicking.rs:363:5
   4: select_test::tests::nuls_become_replacement_char
             at ./examples/select_test.rs:133:9
   5: select_test::tests::nuls_become_replacement_char::{{closure}}
             at ./examples/select_test.rs:128:38
   6: core::ops::function::FnOnce::call_once
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/ops/function.rs:250:5
   7: core::ops::function::FnOnce::call_once
             at /rustc/a70b2ae57713ed0e7411c059d582ab382fc4166a/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test tests::control_chars_become_replacement_char ... FAILED
test tests::nuls_become_replacement_char ... FAILED

failures:

failures:
    tests::control_chars_become_replacement_char
    tests::nuls_become_replacement_char

test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s

error: test failed, to rerun pass `-p cursive --example select_test`

* --nocapture isn't needed for github CI workflow

because it will auto-show this output if it ever fails,
if it doesn't fail, we don't need to see it, it's spammy

* comment typo unicode_segmentation -> unicode-width

refers to the crate
  • Loading branch information
correabuscar authored Jun 10, 2024
1 parent 352ba7d commit 176102a
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ jobs:
- name: Run tests
run: >
cargo test --features "toml markdown ansi termion-backend crossterm-backend" --no-default-features --verbose &&
cargo test --example select_test -- --nocapture
cargo test --example select_test
4 changes: 2 additions & 2 deletions cursive-core/src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,12 @@ impl PrintBuffer {
let width = g.width();
if width == 0 {
// Any zero-width grapheme can be ignored.
// With unicode_segmentation < 0.1.13, this includes control chars.
// With unicode-width < 0.1.13, this includes control chars.
continue;
}

if is_control_char(g) {
// With unicode_segmentation >= 0.1.13, control chars have non-zero width (in
// With unicode-width >= 0.1.13, control chars have non-zero width (in
// practice width = 1).
debug_assert_eq!(
1, width,
Expand Down
9 changes: 4 additions & 5 deletions cursive-core/src/utils/lines/spans/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn test_replacement_char_has_width_1() {
}

#[test]
fn test_control_chars_have_width_1() {
fn test_control_chars_have_width_0_or_1() {
use unicode_width::UnicodeWidthStr;
let control_chars = [
"\u{0000}", "\u{0001}", "\u{0002}", "\u{0003}", "\u{0004}", "\u{0005}", "\u{0006}",
Expand All @@ -52,10 +52,9 @@ fn test_control_chars_have_width_1() {
"it's supposed to be a string of 1 char"
);
let unicode_escape = format!("\\u{{{:04X}}}", c.chars().last().unwrap() as u32);
assert_eq!(
width, 1,
"Width of control character {} is not 1",
unicode_escape
assert!(
(0..=1).contains(&width),
"Width of control character {unicode_escape} is not 0 or 1, it's {width}"
);
}
}
Expand Down
160 changes: 103 additions & 57 deletions cursive/examples/select_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub mod tests {
select.add_item_str("8A\u{008A}\u{008B}\u{008C}\u{008D}\u{008E}\u{008F}\u{0090}\u{0091}\u{0092}\u{0093}thru93");
select.add_item_str("94\u{0094}\u{0095}\u{0096}\u{0097}\u{0098}\u{0099}\u{009A}\u{009B}\u{009C}\u{009D}thru9D");
select.add_item_str("9E\u{009E}\u{009F}thru9F");
//XXX: can't add more lines here, it would cause them to go off view thus fail the is-it-on-screen tests, unless the dialog is made bigger below!

// Sets the callback for when "Enter" is pressed.
select.set_on_submit(show_next_window);
Expand Down Expand Up @@ -125,68 +126,113 @@ pub mod tests {
}

#[test]
fn nuls_become_replacement_char() {
let mut s = BasicSetup::new();
s.hit_keystroke(Key::End);
let screen = s.last_screen().unwrap();
s.dump_debug();
assert_eq!(
screen
.find_occurences("short \u{fffd}nul\u{FFFD} 1str")
.len(),
1,
"nuls aka \\0 in strings are supposed to become the replacement char '\u{fffd}'"
);
}
#[test]
fn control_chars_become_replacement_char() {
fn control_chars_including_nul_when_on_screen() {
let mut s = BasicSetup::new();
s.hit_keystroke(Key::End);
let screen = s.last_screen().unwrap();
s.dump_debug();
let replacement_char = "\u{FFFD} aka \\u{FFFD}";
assert_eq!(
screen.find_occurences("tab�and�newline").len(),
1,
"tabs and newline should've been replaced with replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("b�����������thru15").len(),
1,
"control chars \\x0B thru \\x15 should've been replaced with the replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("16����������thru1F").len(),
1,
"control chars \\x16 thru \\x1F should've been replaced with the replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("7F�only").len(),
1,
"control char \\x7F should've been replaced with the replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("80����������thru89").len(),
1,
"control chars \\x80 thru \\x89 should've been replaced with the replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("8A����������thru93").len(),
1,
"control chars \\x8A thru \\x93 should've been replaced with the replacement char {}",
replacement_char
);
assert_eq!(
screen.find_occurences("9E��thru9F").len(),
1,
"control chars \\x9E thru \\x9F should've been replaced with the replacement char {}",
replacement_char
);
use unicode_width::UnicodeWidthStr;
let width_of_nul = "\0".width();
if !(0..=1).contains(&width_of_nul) {
panic!(
"nul aka \\0 has a width of '{width_of_nul}' instead of the expected one of 0 or 1"
);
}
//we assume that all other control chars have same width as nul for chosing
//which test to perform on them which depends on which unicode-width crate
//version was used: the <=0.1.12 (width==0) or >=0.1.13 (width==1)
//for width==0 we expect control chars to have been deleted from on-screen output
//for width==1 we expect they were replaced with the width 1 replacement char: �
if width_of_nul == 1 {
// unicode-width version =1.1.13 or maybe later too
assert_eq!(
screen
.find_occurences("short \u{fffd}nul\u{FFFD} 1str")
.len(),
1,
"nuls aka \\0 in strings are supposed to become the replacement char '\u{fffd}'"
);
assert_eq!(
screen.find_occurences("tab�and�newline").len(),
1,
"tabs and newline should've been replaced with replacement char {replacement_char}"
);
assert_eq!(
screen.find_occurences("b�����������thru15").len(),
1,
"control chars \\x0B thru \\x15 should've been replaced with the replacement char {replacement_char}",
);
assert_eq!(
screen.find_occurences("16����������thru1F").len(),
1,
"control chars \\x16 thru \\x1F should've been replaced with the replacement char {replacement_char}",
);
assert_eq!(
screen.find_occurences("7F�only").len(),
1,
"control char \\x7F should've been replaced with the replacement char {replacement_char}",
);
assert_eq!(
screen.find_occurences("80����������thru89").len(),
1,
"control chars \\x80 thru \\x89 should've been replaced with the replacement char {replacement_char}",
);
assert_eq!(
screen.find_occurences("8A����������thru93").len(),
1,
"control chars \\x8A thru \\x93 should've been replaced with the replacement char {replacement_char}",
);
assert_eq!(
screen.find_occurences("9E��thru9F").len(),
1,
"control chars \\x9E thru \\x9F should've been replaced with the replacement char {replacement_char}",
);
} else if width_of_nul == 0 {
// unicode-width version <=1.1.12
assert_eq!(
screen.find_occurences("short nul 1str").len(),
1,
"nuls aka \\0 in strings are supposed to deleted from output"
);
assert_eq!(
screen.find_occurences("tabandnewline").len(),
1,
"tabs and newline should've been deleted from output"
);
assert_eq!(
screen.find_occurences("bthru15").len(),
1,
"control chars \\x0B thru \\x15 should've been deleted from output"
);
assert_eq!(
screen.find_occurences("16thru1F").len(),
1,
"control chars \\x16 thru \\x1F should've been deleted from output"
);
assert_eq!(
screen.find_occurences("7Fonly").len(),
1,
"control char \\x7F should've been deleted from output"
);
assert_eq!(
screen.find_occurences("80thru89").len(),
1,
"control chars \\x80 thru \\x89 should've been deleted from output"
);
assert_eq!(
screen.find_occurences("8Athru93").len(),
1,
"control chars \\x8A thru \\x93 should've been deleted from output"
);
assert_eq!(
screen.find_occurences("9Ethru9F").len(),
1,
"control chars \\x9E thru \\x9F should've been deleted from output"
);
} else {
unreachable!();
}
}

#[test]
Expand Down

0 comments on commit 176102a

Please sign in to comment.