tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test.rs (24237B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // Currently the mozdevice API is not safe for multiple requests at the same
      6 // time. It is recommended to run each of the unit tests on its own. Also adb
      7 // specific tests cannot be run in CI yet. To check those locally, also run
      8 // the ignored tests.
      9 //
     10 // Use the following command to accomplish that:
     11 //
     12 //     $ cargo test -- --ignored --test-threads=1
     13 
     14 use crate::*;
     15 
     16 use std::collections::BTreeSet;
     17 use std::panic;
     18 use std::path::PathBuf;
     19 use tempfile::{tempdir, TempDir};
     20 
     21 #[test]
     22 fn read_length_from_valid_string() {
     23    fn test(message: &str) -> Result<usize> {
     24        read_length(&mut io::BufReader::new(message.as_bytes()))
     25    }
     26 
     27    assert_eq!(test("0000").unwrap(), 0);
     28    assert_eq!(test("0001").unwrap(), 1);
     29    assert_eq!(test("000F").unwrap(), 15);
     30    assert_eq!(test("00FF").unwrap(), 255);
     31    assert_eq!(test("0FFF").unwrap(), 4095);
     32    assert_eq!(test("FFFF").unwrap(), 65535);
     33 
     34    assert_eq!(test("FFFF0").unwrap(), 65535);
     35 }
     36 
     37 #[test]
     38 fn read_length_from_invalid_string() {
     39    fn test(message: &str) -> Result<usize> {
     40        read_length(&mut io::BufReader::new(message.as_bytes()))
     41    }
     42 
     43    test("").expect_err("empty string");
     44    test("G").expect_err("invalid hex character");
     45    test("-1").expect_err("negative number");
     46    test("000").expect_err("shorter than 4 bytes");
     47 }
     48 
     49 #[test]
     50 fn encode_message_with_valid_string() {
     51    assert_eq!(encode_message("").unwrap(), "0000".to_string());
     52    assert_eq!(encode_message("a").unwrap(), "0001a".to_string());
     53    assert_eq!(
     54        encode_message(&"a".repeat(15)).unwrap(),
     55        format!("000F{}", "a".repeat(15))
     56    );
     57    assert_eq!(
     58        encode_message(&"a".repeat(255)).unwrap(),
     59        format!("00FF{}", "a".repeat(255))
     60    );
     61    assert_eq!(
     62        encode_message(&"a".repeat(4095)).unwrap(),
     63        format!("0FFF{}", "a".repeat(4095))
     64    );
     65    assert_eq!(
     66        encode_message(&"a".repeat(65535)).unwrap(),
     67        format!("FFFF{}", "a".repeat(65535))
     68    );
     69 }
     70 
     71 #[test]
     72 fn encode_message_with_invalid_string() {
     73    encode_message(&"a".repeat(65536)).expect_err("string lengths exceeds 4 bytes");
     74 }
     75 
     76 fn run_device_test<F>(test: F)
     77 where
     78    F: FnOnce(&Device, &TempDir, &UnixPath) + panic::UnwindSafe,
     79 {
     80    let host = Host {
     81        ..Default::default()
     82    };
     83    let device = host
     84        .device_or_default::<String>(None, AndroidStorageInput::Auto)
     85        .expect("device_or_default");
     86 
     87    let tmp_dir = tempdir().expect("create temp dir");
     88    let response = device
     89        .execute_host_shell_command("echo $EXTERNAL_STORAGE")
     90        .unwrap();
     91    let mut test_root = UnixPathBuf::from(response.trim_end_matches('\n'));
     92    test_root.push("mozdevice");
     93 
     94    let _ = device.remove(&test_root);
     95 
     96    let result = panic::catch_unwind(|| test(&device, &tmp_dir, &test_root));
     97 
     98    let _ = device.kill_forward_all_ports();
     99    // let _ = device.kill_reverse_all_ports();
    100 
    101    assert!(result.is_ok())
    102 }
    103 
    104 #[test]
    105 #[ignore]
    106 fn host_features() {
    107    let host = Host {
    108        ..Default::default()
    109    };
    110 
    111    let set = host.features::<BTreeSet<_>>().expect("to query features");
    112    assert!(set.contains("cmd"));
    113    assert!(set.contains("shell_v2"));
    114 }
    115 
    116 #[test]
    117 #[ignore]
    118 fn host_devices() {
    119    let host = Host {
    120        ..Default::default()
    121    };
    122 
    123    let set: BTreeSet<_> = host.devices().expect("to query devices");
    124    assert_eq!(1, set.len());
    125 }
    126 
    127 #[test]
    128 #[ignore]
    129 fn host_device_or_default() {
    130    let host = Host {
    131        ..Default::default()
    132    };
    133 
    134    let devices: Vec<_> = host.devices().expect("to query devices");
    135    let expected_device = devices.first().expect("found a device");
    136 
    137    let device = host
    138        .device_or_default::<String>(Some(&expected_device.serial), AndroidStorageInput::App)
    139        .expect("connected device with serial");
    140    assert_eq!(device.run_as_package, None);
    141    assert_eq!(device.serial, expected_device.serial);
    142    assert!(device.tempfile.starts_with("/data/local/tmp"));
    143 }
    144 
    145 #[test]
    146 #[ignore]
    147 fn host_device_or_default_invalid_serial() {
    148    let host = Host {
    149        ..Default::default()
    150    };
    151 
    152    host.device_or_default::<String>(Some(&"foobar".to_owned()), AndroidStorageInput::Auto)
    153        .expect_err("invalid serial");
    154 }
    155 
    156 #[test]
    157 #[ignore]
    158 fn host_device_or_default_no_serial() {
    159    let host = Host {
    160        ..Default::default()
    161    };
    162 
    163    let devices: Vec<_> = host.devices().expect("to query devices");
    164    let expected_device = devices.first().expect("found a device");
    165 
    166    let device = host
    167        .device_or_default::<String>(None, AndroidStorageInput::Auto)
    168        .expect("connected device with serial");
    169    assert_eq!(device.serial, expected_device.serial);
    170 }
    171 
    172 #[test]
    173 #[ignore]
    174 fn host_device_or_default_storage_as_app() {
    175    let host = Host {
    176        ..Default::default()
    177    };
    178 
    179    let device = host
    180        .device_or_default::<String>(None, AndroidStorageInput::App)
    181        .expect("connected device");
    182    assert_eq!(device.storage, AndroidStorage::App);
    183 }
    184 
    185 #[test]
    186 #[ignore]
    187 fn host_device_or_default_storage_as_auto() {
    188    let host = Host {
    189        ..Default::default()
    190    };
    191 
    192    let device = host
    193        .device_or_default::<String>(None, AndroidStorageInput::Auto)
    194        .expect("connected device");
    195    assert_eq!(device.storage, AndroidStorage::Sdcard);
    196 }
    197 
    198 #[test]
    199 #[ignore]
    200 fn host_device_or_default_storage_as_internal() {
    201    let host = Host {
    202        ..Default::default()
    203    };
    204 
    205    let device = host
    206        .device_or_default::<String>(None, AndroidStorageInput::Internal)
    207        .expect("connected device");
    208    assert_eq!(device.storage, AndroidStorage::Internal);
    209 }
    210 
    211 #[test]
    212 #[ignore]
    213 fn host_device_or_default_storage_as_sdcard() {
    214    let host = Host {
    215        ..Default::default()
    216    };
    217 
    218    let device = host
    219        .device_or_default::<String>(None, AndroidStorageInput::Sdcard)
    220        .expect("connected device");
    221    assert_eq!(device.storage, AndroidStorage::Sdcard);
    222 }
    223 
    224 #[test]
    225 #[ignore]
    226 fn device_shell_command() {
    227    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    228        assert_eq!(
    229            "Linux\n",
    230            device
    231                .execute_host_shell_command("uname")
    232                .expect("to have shell output")
    233        );
    234    });
    235 }
    236 
    237 #[test]
    238 #[ignore]
    239 fn device_forward_port_hardcoded() {
    240    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    241        assert_eq!(
    242            3035,
    243            device
    244                .forward_port(3035, 3036)
    245                .expect("forwarded local port")
    246        );
    247        // TODO: check with forward --list
    248    });
    249 }
    250 
    251 // #[test]
    252 // #[ignore]
    253 // TODO: "adb server response to `forward tcp:0 ...` was not a u16: \"000559464\"")
    254 // fn device_forward_port_system_allocated() {
    255 //     run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    256 //         let local_port = device.forward_port(0, 3037).expect("local_port");
    257 //         assert_ne!(local_port, 0);
    258 //         // TODO: check with forward --list
    259 //     });
    260 // }
    261 
    262 #[test]
    263 #[ignore]
    264 fn device_kill_forward_port_no_forwarded_port() {
    265    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    266        device
    267            .kill_forward_port(3038)
    268            .expect_err("adb error: listener 'tcp:3038' ");
    269    });
    270 }
    271 
    272 #[test]
    273 #[ignore]
    274 fn device_kill_forward_port_twice() {
    275    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    276        let local_port = device
    277            .forward_port(3039, 3040)
    278            .expect("forwarded local port");
    279        assert_eq!(local_port, 3039);
    280        // TODO: check with forward --list
    281        device
    282            .kill_forward_port(local_port)
    283            .expect("to remove forwarded port");
    284        device
    285            .kill_forward_port(local_port)
    286            .expect_err("adb error: listener 'tcp:3039' ");
    287    });
    288 }
    289 
    290 #[test]
    291 #[ignore]
    292 fn device_kill_forward_all_ports_no_forwarded_port() {
    293    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    294        device
    295            .kill_forward_all_ports()
    296            .expect("to not fail for no forwarded ports");
    297    });
    298 }
    299 
    300 #[test]
    301 #[ignore]
    302 fn device_kill_forward_all_ports_twice() {
    303    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    304        let local_port1 = device
    305            .forward_port(3039, 3040)
    306            .expect("forwarded local port");
    307        assert_eq!(local_port1, 3039);
    308        let local_port2 = device
    309            .forward_port(3041, 3042)
    310            .expect("forwarded local port");
    311        assert_eq!(local_port2, 3041);
    312        // TODO: check with forward --list
    313        device
    314            .kill_forward_all_ports()
    315            .expect("to remove all forwarded ports");
    316        device
    317            .kill_forward_all_ports()
    318            .expect("to not fail for no forwarded ports");
    319    });
    320 }
    321 
    322 #[test]
    323 #[ignore]
    324 fn device_reverse_port_hardcoded() {
    325    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    326        assert_eq!(4035, device.reverse_port(4035, 4036).expect("remote_port"));
    327        // TODO: check with reverse --list
    328    });
    329 }
    330 
    331 // #[test]
    332 // #[ignore]
    333 // TODO: No adb response: ParseInt(ParseIntError { kind: Empty })
    334 // fn device_reverse_port_system_allocated() {
    335 //     run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    336 //         let reverse_port = device.reverse_port(0, 4037).expect("remote port");
    337 //         assert_ne!(reverse_port, 0);
    338 //         // TODO: check with reverse --list
    339 //     });
    340 // }
    341 
    342 #[test]
    343 #[ignore]
    344 fn device_kill_reverse_port_no_reverse_port() {
    345    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    346        device
    347            .kill_reverse_port(4038)
    348            .expect_err("listener 'tcp:4038' not found");
    349    });
    350 }
    351 
    352 // #[test]
    353 // #[ignore]
    354 // TODO: "adb error: adb server response did not contain expected hexstring length: \"\""
    355 // fn device_kill_reverse_port_twice() {
    356 //     run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    357 //         let remote_port = device
    358 //             .reverse_port(4039, 4040)
    359 //             .expect("reversed local port");
    360 //         assert_eq!(remote_port, 4039);
    361 //         // TODO: check with reverse --list
    362 //         device
    363 //             .kill_reverse_port(remote_port)
    364 //             .expect("to remove reverse port");
    365 //         device
    366 //             .kill_reverse_port(remote_port)
    367 //             .expect_err("listener 'tcp:4039' not found");
    368 //     });
    369 // }
    370 
    371 #[test]
    372 #[ignore]
    373 fn device_kill_reverse_all_ports_no_reversed_port() {
    374    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    375        device
    376            .kill_reverse_all_ports()
    377            .expect("to not fail for no reversed ports");
    378    });
    379 }
    380 
    381 #[test]
    382 #[ignore]
    383 fn device_kill_reverse_all_ports_twice() {
    384    run_device_test(|device: &Device, _: &TempDir, _: &UnixPath| {
    385        let local_port1 = device
    386            .forward_port(4039, 4040)
    387            .expect("forwarded local port");
    388        assert_eq!(local_port1, 4039);
    389        let local_port2 = device
    390            .forward_port(4041, 4042)
    391            .expect("forwarded local port");
    392        assert_eq!(local_port2, 4041);
    393        // TODO: check with reverse --list
    394        device
    395            .kill_reverse_all_ports()
    396            .expect("to remove all reversed ports");
    397        device
    398            .kill_reverse_all_ports()
    399            .expect("to not fail for no reversed ports");
    400    });
    401 }
    402 
    403 #[test]
    404 #[ignore]
    405 fn device_push_pull_text_file() {
    406    run_device_test(
    407        |device: &Device, _: &TempDir, remote_root_path: &UnixPath| {
    408            let content = "test";
    409            let remote_path = remote_root_path.join("foo.txt");
    410 
    411            device
    412                .push(
    413                    &mut io::BufReader::new(content.as_bytes()),
    414                    &remote_path,
    415                    0o777,
    416                )
    417                .expect("file has been pushed");
    418 
    419            let file_content = device
    420                .execute_host_shell_command(&format!("cat {}", remote_path.display()))
    421                .expect("host shell command for 'cat' to succeed");
    422 
    423            assert_eq!(file_content, content);
    424 
    425            // And as second step pull it off the device.
    426            let mut buffer = Vec::new();
    427            device
    428                .pull(&remote_path, &mut buffer)
    429                .expect("file has been pulled");
    430            assert_eq!(buffer, content.as_bytes());
    431        },
    432    );
    433 }
    434 
    435 #[test]
    436 #[ignore]
    437 fn device_push_pull_large_binary_file() {
    438    run_device_test(
    439        |device: &Device, _: &TempDir, remote_root_path: &UnixPath| {
    440            let remote_path = remote_root_path.join("foo.binary");
    441 
    442            let mut content = Vec::new();
    443 
    444            // Needs to be larger than 64kB to test multiple chunks.
    445            for i in 0..100000u32 {
    446                content.push('0' as u8 + (i % 10) as u8);
    447            }
    448 
    449            device
    450                .push(
    451                    &mut std::io::Cursor::new(content.clone()),
    452                    &remote_path,
    453                    0o777,
    454                )
    455                .expect("large file has been pushed");
    456 
    457            let output = device
    458                .execute_host_shell_command(&format!("ls -l {}", remote_path.display()))
    459                .expect("host shell command for 'ls' to succeed");
    460 
    461            assert!(output.contains(remote_path.to_str().unwrap()));
    462 
    463            let mut buffer = Vec::new();
    464 
    465            device
    466                .pull(&remote_path, &mut buffer)
    467                .expect("large binary file has been pulled");
    468            assert_eq!(buffer, content);
    469        },
    470    );
    471 }
    472 
    473 #[test]
    474 #[ignore]
    475 fn device_push_permission() {
    476    run_device_test(
    477        |device: &Device, _: &TempDir, remote_root_path: &UnixPath| {
    478            fn adjust_mode(mode: u32) -> u32 {
    479                // Adjust the mode by copying the user permissions to
    480                // group and other as indicated in
    481                // [send_impl](https://android.googlesource.com/platform/system/core/+/master/adb/daemon/file_sync_service.cpp#516).
    482                // This ensures that group and other can both access a
    483                // file if the user can access it.
    484                let mut m = mode & 0o777;
    485                m |= (m >> 3) & 0o070;
    486                m |= (m >> 3) & 0o007;
    487                m
    488            }
    489 
    490            fn get_permissions(mode: u32) -> String {
    491                // Convert the mode integer into the string representation
    492                // of the mode returned by `ls`. This assumes the object is
    493                // a file and not a directory.
    494                let mut perms = vec!["-", "r", "w", "x", "r", "w", "x", "r", "w", "x"];
    495                let mut bit_pos = 0;
    496                while bit_pos < 9 {
    497                    if (1 << bit_pos) & mode == 0 {
    498                        perms[9 - bit_pos] = "-"
    499                    }
    500                    bit_pos += 1;
    501                }
    502                perms.concat()
    503            }
    504            let content = "test";
    505            let remote_path = remote_root_path.join("foo.bar");
    506 
    507            // First push the file to the device
    508            let modes = vec![0o421, 0o644, 0o666, 0o777];
    509            for mode in modes {
    510                let adjusted_mode = adjust_mode(mode);
    511                let adjusted_perms = get_permissions(adjusted_mode);
    512                device
    513                    .push(
    514                        &mut io::BufReader::new(content.as_bytes()),
    515                        &remote_path,
    516                        mode,
    517                    )
    518                    .expect("file has been pushed");
    519 
    520                let output = device
    521                    .execute_host_shell_command(&format!("ls -l {}", remote_path.display()))
    522                    .expect("host shell command for 'ls' to succeed");
    523 
    524                assert!(output.contains(remote_path.to_str().unwrap()));
    525                assert!(output.starts_with(&adjusted_perms));
    526            }
    527 
    528            let output = device
    529                .execute_host_shell_command(&format!("ls -ld {}", remote_root_path.display()))
    530                .expect("host shell command for 'ls parent' to succeed");
    531 
    532            assert!(output.contains(remote_root_path.to_str().unwrap()));
    533            assert!(output.starts_with("drwxrwxrwx"));
    534        },
    535    );
    536 }
    537 
    538 #[test]
    539 #[ignore]
    540 fn device_pull_fails_for_missing_file() {
    541    run_device_test(
    542        |device: &Device, _: &TempDir, remote_root_path: &UnixPath| {
    543            let mut buffer = Vec::new();
    544 
    545            device
    546                .pull(&remote_root_path.join("missing"), &mut buffer)
    547                .expect_err("missing file should not be pulled");
    548        },
    549    );
    550 }
    551 
    552 #[test]
    553 #[ignore]
    554 fn device_push_and_list_dir() {
    555    run_device_test(
    556        |device: &Device, tmp_dir: &TempDir, remote_root_path: &UnixPath| {
    557            let files = ["foo1.bar", "foo2.bar", "bar/foo3.bar", "bar/more/foo3.bar"];
    558 
    559            for file in files.iter() {
    560                let path = tmp_dir.path().join(Path::new(file));
    561                let _ = std::fs::create_dir_all(path.parent().unwrap());
    562 
    563                let f = File::create(path).expect("to create file");
    564                let mut f = io::BufWriter::new(f);
    565                f.write_all(file.as_bytes()).expect("to write data");
    566            }
    567 
    568            device
    569                .push_dir(tmp_dir.path(), &remote_root_path, 0o777)
    570                .expect("to push_dir");
    571 
    572            for file in files.iter() {
    573                let path = append_components(remote_root_path, Path::new(file)).unwrap();
    574                let output = device
    575                    .execute_host_shell_command(&format!("ls {}", path.display()))
    576                    .expect("host shell command for 'ls' to succeed");
    577 
    578                assert!(output.contains(path.to_str().unwrap()));
    579            }
    580 
    581            let mut listings = device.list_dir(&remote_root_path).expect("to list_dir");
    582            listings.sort();
    583            assert_eq!(
    584                listings,
    585                vec![
    586                    RemoteDirEntry {
    587                        depth: 0,
    588                        name: "foo1.bar".to_string(),
    589                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    590                            mode: 0b110110000,
    591                            size: 8
    592                        })
    593                    },
    594                    RemoteDirEntry {
    595                        depth: 0,
    596                        name: "foo2.bar".to_string(),
    597                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    598                            mode: 0b110110000,
    599                            size: 8
    600                        })
    601                    },
    602                    RemoteDirEntry {
    603                        depth: 0,
    604                        name: "bar".to_string(),
    605                        metadata: RemoteMetadata::RemoteDir
    606                    },
    607                    RemoteDirEntry {
    608                        depth: 1,
    609                        name: "bar/foo3.bar".to_string(),
    610                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    611                            mode: 0b110110000,
    612                            size: 12
    613                        })
    614                    },
    615                    RemoteDirEntry {
    616                        depth: 1,
    617                        name: "bar/more".to_string(),
    618                        metadata: RemoteMetadata::RemoteDir
    619                    },
    620                    RemoteDirEntry {
    621                        depth: 2,
    622                        name: "bar/more/foo3.bar".to_string(),
    623                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    624                            mode: 0b110110000,
    625                            size: 17
    626                        })
    627                    }
    628                ]
    629            );
    630        },
    631    );
    632 }
    633 
    634 #[test]
    635 #[ignore]
    636 fn device_push_and_pull_dir() {
    637    run_device_test(
    638        |device: &Device, tmp_dir: &TempDir, remote_root_path: &UnixPath| {
    639            let files = ["foo1.bar", "foo2.bar", "bar/foo3.bar", "bar/more/foo3.bar"];
    640 
    641            let src_dir = tmp_dir.path().join(Path::new("src"));
    642            let dest_dir = tmp_dir.path().join(Path::new("src"));
    643 
    644            for file in files.iter() {
    645                let path = src_dir.join(Path::new(file));
    646                let _ = std::fs::create_dir_all(path.parent().unwrap());
    647 
    648                let f = File::create(path).expect("to create file");
    649                let mut f = io::BufWriter::new(f);
    650                f.write_all(file.as_bytes()).expect("to write data");
    651            }
    652 
    653            device
    654                .push_dir(&src_dir, &remote_root_path, 0o777)
    655                .expect("to push_dir");
    656 
    657            device
    658                .pull_dir(remote_root_path, &dest_dir)
    659                .expect("to pull_dir");
    660 
    661            for file in files.iter() {
    662                let path = dest_dir.join(Path::new(file));
    663                let mut f = File::open(path).expect("to open file");
    664                let mut buf = String::new();
    665                f.read_to_string(&mut buf).expect("to read content");
    666                assert_eq!(buf, *file);
    667            }
    668        },
    669    )
    670 }
    671 
    672 #[test]
    673 #[ignore]
    674 fn device_push_and_list_dir_flat() {
    675    run_device_test(
    676        |device: &Device, tmp_dir: &TempDir, remote_root_path: &UnixPath| {
    677            let content = "test";
    678 
    679            let files = [
    680                PathBuf::from("foo1.bar"),
    681                PathBuf::from("foo2.bar"),
    682                PathBuf::from("bar").join("foo3.bar"),
    683            ];
    684 
    685            for file in files.iter() {
    686                let path = tmp_dir.path().join(&file);
    687                let _ = std::fs::create_dir_all(path.parent().unwrap());
    688 
    689                let f = File::create(path).expect("to create file");
    690                let mut f = io::BufWriter::new(f);
    691                f.write_all(content.as_bytes()).expect("to write data");
    692            }
    693 
    694            device
    695                .push_dir(tmp_dir.path(), &remote_root_path, 0o777)
    696                .expect("to push_dir");
    697 
    698            for file in files.iter() {
    699                let path = append_components(remote_root_path, file).unwrap();
    700                let output = device
    701                    .execute_host_shell_command(&format!("ls {}", path.display()))
    702                    .expect("host shell command for 'ls' to succeed");
    703 
    704                assert!(output.contains(path.to_str().unwrap()));
    705            }
    706 
    707            let mut listings = device
    708                .list_dir_flat(&remote_root_path, 7, "prefix".to_string())
    709                .expect("to list_dir_flat");
    710            listings.sort();
    711            assert_eq!(
    712                listings,
    713                vec![
    714                    RemoteDirEntry {
    715                        depth: 7,
    716                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    717                            mode: 0b110110000,
    718                            size: 4
    719                        }),
    720                        name: "prefix/foo1.bar".to_string(),
    721                    },
    722                    RemoteDirEntry {
    723                        depth: 7,
    724                        metadata: RemoteMetadata::RemoteFile(RemoteFileMetadata {
    725                            mode: 0b110110000,
    726                            size: 4
    727                        }),
    728                        name: "prefix/foo2.bar".to_string(),
    729                    },
    730                    RemoteDirEntry {
    731                        depth: 7,
    732                        metadata: RemoteMetadata::RemoteDir,
    733                        name: "prefix/bar".to_string(),
    734                    },
    735                ]
    736            );
    737        },
    738    );
    739 }
    740 
    741 #[test]
    742 fn format_own_device_error_types() {
    743    assert_eq!(
    744        format!("{}", DeviceError::InvalidStorage),
    745        "Invalid storage".to_string()
    746    );
    747    assert_eq!(
    748        format!("{}", DeviceError::MissingPackage),
    749        "Missing package".to_string()
    750    );
    751    assert_eq!(
    752        format!("{}", DeviceError::MultipleDevices),
    753        "Multiple Android devices online".to_string()
    754    );
    755 
    756    assert_eq!(
    757        format!("{}", DeviceError::Adb("foo".to_string())),
    758        "foo".to_string()
    759    );
    760 }