dropbox-sdk 0.19.1

Rust bindings to the Dropbox API, generated by Stone from the official spec.
Documentation
use dropbox_sdk::default_client::UserAuthDefaultClient;
use dropbox_sdk::files;
use std::collections::HashSet;
use std::sync::Arc;

mod common;

#[test]
#[ignore] // very time-consuming to run; should be run separately
fn list_folder_recursive() {
    let auth = dropbox_sdk::oauth2::get_auth_from_env_or_prompt();
    let client = Arc::new(UserAuthDefaultClient::new(auth));

    const FOLDER: &str = "/list_folder_recursive";
    const FOLDER_INNER: &str = "/list_folder_recursive/subfolder";
    const NUM_FILES: u32 = 30;
    const FILE_SIZE: usize = 100;

    common::create_clean_folder(client.as_ref(), FOLDER);
    common::create_clean_folder(client.as_ref(), FOLDER_INNER);

    let (files_a, _) = common::create_files(client.clone(), FOLDER, NUM_FILES, FILE_SIZE);
    let (files_b, _) = common::create_files(client.clone(), FOLDER_INNER, NUM_FILES, FILE_SIZE);

    let mut files = HashSet::new();
    for i in 0..NUM_FILES {
        files.insert(files_a(i));
        files.insert(files_b(i));
    }

    println!("Created a bunch of files. Now listing them.");

    let mut process_entries = |entries| {
        for metadata in entries {
            match metadata {
                files::Metadata::File(files::FileMetadata { path_lower, .. }) => {
                    let path_lower = path_lower.expect("missing path_lower in response");
                    assert!(
                        files.remove(&path_lower),
                        "got unexpected path {}",
                        path_lower
                    );
                }
                files::Metadata::Folder(files::FolderMetadata { path_lower, .. }) => {
                    let path_lower = path_lower.expect("missing path_lower in response");
                    assert!(matches!(path_lower.as_str(), FOLDER | FOLDER_INNER));
                }
                other => panic!("unexpected {:?}", other),
            }
        }
    };

    println!("list_folder");
    let (mut cursor, mut has_more) = match files::list_folder(
        client.as_ref(),
        &files::ListFolderArg::new(FOLDER.to_owned())
            .with_recursive(true)
            .with_limit(10),
    ) {
        Ok(files::ListFolderResult {
            entries,
            cursor,
            has_more,
            ..
        }) => {
            println!("{} entries", entries.len());
            process_entries(entries);
            assert!(has_more, "expected has_more from list_folder");
            (cursor, has_more)
        }
        Err(e) => panic!("unexpected result from list_folder: {:?}", e),
    };

    while has_more {
        println!("list_folder_continue");
        let next = match files::list_folder_continue(
            client.as_ref(),
            &files::ListFolderContinueArg::new(cursor.clone()),
        ) {
            Ok(files::ListFolderResult {
                entries,
                cursor,
                has_more,
                ..
            }) => {
                println!("{} entries", entries.len());
                process_entries(entries);
                (cursor, has_more)
            }
            Err(e) => panic!("unexpected result from list_folder_continue: {:?}", e),
        };
        cursor = next.0;
        has_more = next.1;
    }

    assert!(files.is_empty(), "leftover unfound files: {:?}", files);
}