CINXE.COM
GitHub - younata/Nimble: A Matcher Framework for Swift and Objective-C
<!DOCTYPE html> <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true" > <head> <meta charset="utf-8"> <link rel="dns-prefetch" href="https://github.githubassets.com"> <link rel="dns-prefetch" href="https://avatars.githubusercontent.com"> <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com"> <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/"> <link rel="preconnect" href="https://github.githubassets.com" crossorigin> <link rel="preconnect" href="https://avatars.githubusercontent.com"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-74231a1f3bbb.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-8a995f0bacd4.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-f37fb7684b1f.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-9ac301c3ebe5.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-cd826e8636dc.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-f91b0f603451.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-83beb16e0ecf.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-6e122dab64fc.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-18119e682df0.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-225433424a87.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-cba26849680f.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-b6cb3703b934.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-ea73c9cb5377.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-4fce88777fa8.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-0210be90f4d3.css" /> <script type="application/json" id="client-env">{"locale":"en","featureFlags":["contentful_lp_flex_features_actions","contentful_lp_flex_features_codespaces","contentful_lp_flex_features_code_review","contentful_lp_flex_features_code_search","contentful_lp_flex_features_discussions","contentful_lp_flex_features_issues","copilot_immersive_issue_preview","copilot_new_references_ui","copilot_chat_repo_custom_instructions_preview","copilot_no_floating_button","copilot_topics_as_references","copilot_read_shared_conversation","copilot_duplicate_thread","dotcom_chat_client_side_skills","experimentation_azure_variant_endpoint","failbot_handle_non_errors","geojson_azure_maps","ghost_pilot_confidence_truncation_25","ghost_pilot_confidence_truncation_40","github_models_gateway_parse_params","github_models_o3_mini_streaming","insert_before_patch","issues_react_remove_placeholders","issues_react_blur_item_picker_on_close","issues_advanced_search_nested_ownership_filters","issues_dashboard_no_redirects","marketing_pages_search_explore_provider","primer_react_css_modules_ga","react_data_router_pull_requests","react_override_default_key","remove_child_patch","sample_network_conn_type","swp_enterprise_contact_form","site_copilot_pro_plus","site_proxima_australia_update","viewscreen_sandbox","issues_react_create_milestone","issues_react_cache_fix_workaround","lifecycle_label_name_updates","copilot_task_oriented_assistive_prompts","issue_types_prevent_private_type_creation","refresh_image_video_src","react_router_dispose_on_disconnect","codespaces_prebuild_region_target_update","turbo_app_id_restore","copilot_code_review_sign_up_closed"]}</script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-89488af87085.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover_js-9da652f58479.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_arianotify-polyfill_ariaNotify-polyfill_js-node_modules_github_mi-3abb8f-46b9f4874d95.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_failbot_failbot_ts-952d624642a1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/environment-f04cb2a9fc8c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_primer_behaviors_dist_esm_index_mjs-0dbb79f97f8f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_selector-observer_dist_index_esm_js-f690fd9ae3d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_relative-time-element_dist_index_js-62d275b7ddd9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_text-expander-element_dist_index_js-78748950cb0c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_auto-complete-element_dist_index_js-node_modules_github_catalyst_-8e9f78-a90ac05d2469.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-b5f1d7-a1760ffda83d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_markdown-toolbar-element_dist_index_js-ceef33f593fa.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_primer_view-co-c44a69-efa32db3a345.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-394f8eb34f19.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-fdc7225e42cc.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_braintree_browser-detection_dist_browser-detection_js-node_modules_githu-2906d7-2a07a295af40.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lit-html_lit-html_js-be8cb88f481b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_morphdom_dist_morphdom-e-7c534c-a4a1922eb55f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_turbo_dist_turbo_es2017-esm_js-a03ee12d659a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-893f9f-b6294cf703b7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_color-convert_index_js-e3180fe3bcb3.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_quote-selection_dist_index_js-node_modules_github_session-resume_-947061-e7a6c4a19f98.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_updatable-content_updatable-content_ts-62f3e9c52ece.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_task-list_ts-app_assets_modules_github_sso_ts-ui_packages-900dde-768abe60b1f8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_sticky-scroll-into-view_ts-3e000c5d31a9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_ajax-error_ts-app_assets_modules_github_behaviors_include-d0d0a6-e7f74ee74d91.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_commenting_edit_ts-app_assets_modules_github_behaviors_ht-83c235-4bcbbbfbe1d4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-1884a015a8c7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_catalyst_lib_index_js-f6223d90c7ba.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-01e85cd1be94.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_virtualized-list_es_index_js-node_modules_github_template-parts_lib_index_js-94dc7a2157c1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-70450e-4b93df70b903.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_ref-selector_ts-52913063a0b9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/codespaces-b419a25ee02f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-3eebbd-0763620ad7bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_decorators_js-node_modules_delegated-events_di-e161aa-9d41fb1b6c9e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_github_remote--3c9c82-b71ef90fbdc7.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repositories-10217e4e5a53.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_github_catalyst_lib_inde-dbbea9-26cce2010167.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/code-menu-d6d3c94ee97e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-99bc880bd101.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-core-25e9ddbd9991.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-f1bca44e0926.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-cf2f2ab8dab4.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_emotion_is-prop-valid_dist_emotion-is-prop-valid_esm_js-node_modules_emo-434cb6-95f395b76298.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-e7dcdd-9a233856b02c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover-fn_js-55fea94174bf.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-0e7e3f0bfc4b.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.a490b7c9fa319e5cb069.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.a490b7c9fa319e5cb069.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.1bcff9205c241e99cff2.module.css" /> <title>GitHub - younata/Nimble: A Matcher Framework for Swift and Objective-C</title> <meta name="route-pattern" content="/:user_id/:repository" data-turbo-transient> <meta name="route-controller" content="files" data-turbo-transient> <meta name="route-action" content="disambiguate" data-turbo-transient> <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb"> <meta name="request-id" content="EC6C:9B103:35F74E:466496:67F1FF68" data-pjax-transient="true"/><meta name="html-safe-nonce" content="93b2b6ac9f66ccd03053b44486d5493703b4557fb1bb5f1f278e3b260bca5f36" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQzZDOjlCMTAzOjM1Rjc0RTo0NjY0OTY6NjdGMUZGNjgiLCJ2aXNpdG9yX2lkIjoiNTgwMzIyMjgwNjkzNzMzNzcwNCIsInJlZ2lvbl9lZGdlIjoic291dGhlYXN0YXNpYSIsInJlZ2lvbl9yZW5kZXIiOiJzb3V0aGVhc3Rhc2lhIn0=" data-pjax-transient="true"/><meta name="visitor-hmac" content="1a9bd190c1719d112c231945e64698c8e45465ab824668f266f55cc7c1b43b11" data-pjax-transient="true"/> <meta name="hovercard-subject-tag" content="repository:338929302" data-turbo-transient> <meta name="github-keyboard-shortcuts" content="repository,copilot" data-turbo-transient="true" /> <meta name="selected-link" value="repo_source" data-turbo-transient> <link rel="assets" href="https://github.githubassets.com/"> <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I"> <meta name="octolytics-url" content="https://collector.github.com/github/collect" /> <meta name="analytics-location" content="/<user-name>/<repo-name>" data-turbo-transient="true" /> <meta name="user-login" content=""> <meta name="viewport" content="width=device-width"> <meta name="description" content="A Matcher Framework for Swift and Objective-C. Contribute to younata/Nimble development by creating an account on GitHub."> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub"> <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub"> <meta property="fb:app_id" content="1401488693436528"> <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/younata/Nimble" /> <meta name="twitter:image" content="https://opengraph.githubassets.com/77b04446b23fd4a055359c75f33f035710569483188eef2b8ae213bd1e8378a0/younata/Nimble" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="GitHub - younata/Nimble: A Matcher Framework for Swift and Objective-C" /><meta name="twitter:description" content="A Matcher Framework for Swift and Objective-C. Contribute to younata/Nimble development by creating an account on GitHub." /> <meta property="og:image" content="https://opengraph.githubassets.com/77b04446b23fd4a055359c75f33f035710569483188eef2b8ae213bd1e8378a0/younata/Nimble" /><meta property="og:image:alt" content="A Matcher Framework for Swift and Objective-C. Contribute to younata/Nimble development by creating an account on GitHub." /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="GitHub - younata/Nimble: A Matcher Framework for Swift and Objective-C" /><meta property="og:url" content="https://github.com/younata/Nimble" /><meta property="og:description" content="A Matcher Framework for Swift and Objective-C. Contribute to younata/Nimble development by creating an account on GitHub." /> <meta name="hostname" content="github.com"> <meta name="expected-hostname" content="github.com"> <meta http-equiv="x-pjax-version" content="02a7054966f6e852d6433d8e36068459d9bdce0ac44a7bf3404443f2caf9e686" data-turbo-track="reload"> <meta http-equiv="x-pjax-csp-version" content="e26f9f0ba624ee85cc7ac057d8faa8618a4f25a85eab052c33d018ac0f6b1a46" data-turbo-track="reload"> <meta http-equiv="x-pjax-css-version" content="205838381d6e5f35c535dbb12458f905bc43e0b186c86bf75aabbd0c0f36537c" data-turbo-track="reload"> <meta http-equiv="x-pjax-js-version" content="69224d30d454d07137548bdbb460eb0ecb2b69d9b4469b956de88fbfafc08d83" data-turbo-track="reload"> <meta name="turbo-cache-control" content="no-preview" data-turbo-transient=""> <meta data-hydrostats="publish"> <meta name="go-import" content="github.com/younata/Nimble git https://github.com/younata/Nimble.git"> <meta name="octolytics-dimension-user_id" content="285321" /><meta name="octolytics-dimension-user_login" content="younata" /><meta name="octolytics-dimension-repository_id" content="338929302" /><meta name="octolytics-dimension-repository_nwo" content="younata/Nimble" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="true" /><meta name="octolytics-dimension-repository_parent_id" content="21301381" /><meta name="octolytics-dimension-repository_parent_nwo" content="Quick/Nimble" /><meta name="octolytics-dimension-repository_network_root_id" content="21301381" /><meta name="octolytics-dimension-repository_network_root_nwo" content="Quick/Nimble" /> <link rel="canonical" href="https://github.com/younata/Nimble" data-turbo-transient> <meta name="turbo-body-classes" content="logged-out env-production page-responsive"> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <meta name="release" content="7781a360220ef1e07dad0bd10fec7e003eb6aa47"> <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000"> <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png"> <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon"> <meta name="theme-color" content="#1e2327"> <meta name="color-scheme" content="light dark" /> <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials"> </head> <body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div class="position-relative header-wrapper js-header-wrapper "> <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a> <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full"> <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span> </span> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ui-commands_ui-commands_ts-2d52c8e72e64.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-1edadb4bd04c.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.a490b7c9fa319e5cb069.module.css" /> <react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script> <div data-target="react-partial.reactRoot"></div> </react-partial> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-94fd67-4898d1bf4b51.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/sessions-45d6658f8b6b.js"></script> <header class="HeaderMktg header-logged-out js-details-container js-header Details f4 py-3" role="banner" data-is-top="true" data-color-mode=light data-light-theme=light data-dark-theme=dark> <h2 class="sr-only">Navigation Menu</h2> <button type="button" class="HeaderMktg-backdrop d-lg-none border-0 position-fixed top-0 left-0 width-full height-full js-details-target" aria-label="Toggle navigation"> <span class="d-none">Toggle navigation</span> </button> <div class="d-flex flex-column flex-lg-row flex-items-center px-3 px-md-4 px-lg-5 height-full position-relative z-1"> <div class="d-flex flex-justify-between flex-items-center width-full width-lg-auto"> <div class="flex-1"> <button aria-label="Toggle navigation" aria-expanded="false" type="button" data-view-component="true" class="js-details-target js-nav-padding-recalculate js-header-menu-toggle Button--link Button--medium Button d-lg-none color-fg-inherit p-1"> <span class="Button-content"> <span class="Button-label"><div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div> <div class="HeaderMenu-toggle-bar rounded my-1"></div></span> </span> </button> </div> <a class="mr-lg-3 color-fg-inherit flex-order-2 js-prevent-focus-on-mobile-nav" href="/" aria-label="Homepage" data-analytics-event="{"category":"Marketing nav","action":"click to go to homepage","label":"ref_page:Marketing;ref_cta:Logomark;ref_loc:Header"}"> <svg height="32" aria-hidden="true" viewBox="0 0 24 24" version="1.1" width="32" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <div class="flex-1 flex-order-2 text-right"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble" class="HeaderMenu-link HeaderMenu-button d-inline-flex d-lg-none flex-order-1 f5 no-underline border color-border-default rounded-2 px-2 py-1 color-fg-inherit js-prevent-focus-on-mobile-nav" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="845b297be0a842bc5ed4e17f1f9d3c15aa1e94f35cb220b32b22e903f0891c74" data-analytics-event="{"category":"Marketing nav","action":"click to Sign in","label":"ref_page:Marketing;ref_cta:Sign in;ref_loc:Header"}" > Sign in </a> </div> </div> <div class="HeaderMenu js-header-menu height-fit position-lg-relative d-lg-flex flex-column flex-auto top-0"> <div class="HeaderMenu-wrapper d-flex flex-column flex-self-start flex-lg-row flex-auto rounded rounded-lg-0"> <nav class="HeaderMenu-nav" aria-label="Global"> <ul class="d-lg-flex list-style-none"> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Product <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"github_copilot","context":"product","tag":"link","label":"github_copilot_link_product_navbar"}" href="https://github.com/features/copilot"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Copilot</div> Write better code with AI </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"github_advanced_security","context":"product","tag":"link","label":"github_advanced_security_link_product_navbar"}" href="https://github.com/security/advanced-security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Advanced Security</div> Find and fix vulnerabilities </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"actions","context":"product","tag":"link","label":"actions_link_product_navbar"}" href="https://github.com/features/actions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-workflow color-fg-subtle mr-3"> <path d="M1 3a2 2 0 0 1 2-2h6.5a2 2 0 0 1 2 2v6.5a2 2 0 0 1-2 2H7v4.063C7 16.355 7.644 17 8.438 17H12.5v-2.5a2 2 0 0 1 2-2H21a2 2 0 0 1 2 2V21a2 2 0 0 1-2 2h-6.5a2 2 0 0 1-2-2v-2.5H8.437A2.939 2.939 0 0 1 5.5 15.562V11.5H3a2 2 0 0 1-2-2Zm2-.5a.5.5 0 0 0-.5.5v6.5a.5.5 0 0 0 .5.5h6.5a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5ZM14.5 14a.5.5 0 0 0-.5.5V21a.5.5 0 0 0 .5.5H21a.5.5 0 0 0 .5-.5v-6.5a.5.5 0 0 0-.5-.5Z"></path> </svg> <div> <div class="color-fg-default h4">Actions</div> Automate any workflow </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"codespaces","context":"product","tag":"link","label":"codespaces_link_product_navbar"}" href="https://github.com/features/codespaces"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-codespaces color-fg-subtle mr-3"> <path d="M3.5 3.75C3.5 2.784 4.284 2 5.25 2h13.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 18.75 13H5.25a1.75 1.75 0 0 1-1.75-1.75Zm-2 12c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v4a1.75 1.75 0 0 1-1.75 1.75H3.25a1.75 1.75 0 0 1-1.75-1.75ZM5.25 3.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h13.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Zm-2 12a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h17.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25Z"></path><path d="M10 17.75a.75.75 0 0 1 .75-.75h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> <div> <div class="color-fg-default h4">Codespaces</div> Instant dev environments </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"issues","context":"product","tag":"link","label":"issues_link_product_navbar"}" href="https://github.com/features/issues"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-issue-opened color-fg-subtle mr-3"> <path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Zm9.5 2a2 2 0 1 1-.001-3.999A2 2 0 0 1 12 14Z"></path> </svg> <div> <div class="color-fg-default h4">Issues</div> Plan and track work </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"code_review","context":"product","tag":"link","label":"code_review_link_product_navbar"}" href="https://github.com/features/code-review"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-review color-fg-subtle mr-3"> <path d="M10.3 6.74a.75.75 0 0 1-.04 1.06l-2.908 2.7 2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M1.5 4.25c0-.966.784-1.75 1.75-1.75h17.5c.966 0 1.75.784 1.75 1.75v12.5a1.75 1.75 0 0 1-1.75 1.75h-9.69l-3.573 3.573A1.458 1.458 0 0 1 5 21.043V18.5H3.25a1.75 1.75 0 0 1-1.75-1.75ZM3.25 4a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h2.5a.75.75 0 0 1 .75.75v3.19l3.72-3.72a.749.749 0 0 1 .53-.22h10a.25.25 0 0 0 .25-.25V4.25a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Review</div> Manage code changes </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"discussions","context":"product","tag":"link","label":"discussions_link_product_navbar"}" href="https://github.com/features/discussions"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Discussions</div> Collaborate outside of code </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"code_search","context":"product","tag":"link","label":"code_search_link_product_navbar"}" href="https://github.com/features/code-search"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-code-square color-fg-subtle mr-3"> <path d="M10.3 8.24a.75.75 0 0 1-.04 1.06L7.352 12l2.908 2.7a.75.75 0 1 1-1.02 1.1l-3.5-3.25a.75.75 0 0 1 0-1.1l3.5-3.25a.75.75 0 0 1 1.06.04Zm3.44 1.06a.75.75 0 1 1 1.02-1.1l3.5 3.25a.75.75 0 0 1 0 1.1l-3.5 3.25a.75.75 0 1 1-1.02-1.1l2.908-2.7-2.908-2.7Z"></path><path d="M2 3.75C2 2.784 2.784 2 3.75 2h16.5c.966 0 1.75.784 1.75 1.75v16.5A1.75 1.75 0 0 1 20.25 22H3.75A1.75 1.75 0 0 1 2 20.25Zm1.75-.25a.25.25 0 0 0-.25.25v16.5c0 .138.112.25.25.25h16.5a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25Z"></path> </svg> <div> <div class="color-fg-default h4">Code Search</div> Find more, search less </div> </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="product-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="product-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"all_features","context":"product","tag":"link","label":"all_features_link_product_navbar"}" href="https://github.com/features"> All features </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"documentation","context":"product","tag":"link","label":"documentation_link_product_navbar"}" href="https://docs.github.com"> Documentation <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"github_skills","context":"product","tag":"link","label":"github_skills_link_product_navbar"}" href="https://skills.github.com"> GitHub Skills <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"blog","context":"product","tag":"link","label":"blog_link_product_navbar"}" href="https://github.blog"> Blog <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Solutions <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 pb-lg-3 mb-3 mb-lg-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-company-size-heading">By company size</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-company-size-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"enterprises","context":"solutions","tag":"link","label":"enterprises_link_solutions_navbar"}" href="https://github.com/enterprise"> Enterprises </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"small_and_medium_teams","context":"solutions","tag":"link","label":"small_and_medium_teams_link_solutions_navbar"}" href="https://github.com/team"> Small and medium teams </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"startups","context":"solutions","tag":"link","label":"startups_link_solutions_navbar"}" href="https://github.com/enterprise/startups"> Startups </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"nonprofits","context":"solutions","tag":"link","label":"nonprofits_link_solutions_navbar"}" href="/solutions/industry/nonprofits"> Nonprofits </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-use-case-heading">By use case</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-use-case-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devsecops","context":"solutions","tag":"link","label":"devsecops_link_solutions_navbar"}" href="/solutions/use-case/devsecops"> DevSecOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devops","context":"solutions","tag":"link","label":"devops_link_solutions_navbar"}" href="/solutions/use-case/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ci_cd","context":"solutions","tag":"link","label":"ci_cd_link_solutions_navbar"}" href="/solutions/use-case/ci-cd"> CI/CD </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all_use_cases","context":"solutions","tag":"link","label":"view_all_use_cases_link_solutions_navbar"}" href="/solutions/use-case"> View all use cases </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="solutions-by-industry-heading">By industry</span> <ul class="list-style-none f5" aria-labelledby="solutions-by-industry-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"healthcare","context":"solutions","tag":"link","label":"healthcare_link_solutions_navbar"}" href="/solutions/industry/healthcare"> Healthcare </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"financial_services","context":"solutions","tag":"link","label":"financial_services_link_solutions_navbar"}" href="/solutions/industry/financial-services"> Financial services </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"manufacturing","context":"solutions","tag":"link","label":"manufacturing_link_solutions_navbar"}" href="/solutions/industry/manufacturing"> Manufacturing </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"government","context":"solutions","tag":"link","label":"government_link_solutions_navbar"}" href="/solutions/industry/government"> Government </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all_industries","context":"solutions","tag":"link","label":"view_all_industries_link_solutions_navbar"}" href="/solutions/industry"> View all industries </a></li> </ul> </div> </div> <div class="HeaderMenu-trailing-link rounded-bottom-2 flex-shrink-0 mt-lg-4 px-lg-4 py-4 py-lg-3 f5 text-semibold"> <a href="/solutions"> View all solutions <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-right HeaderMenu-trailing-link-icon"> <path d="M6.22 3.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L9.94 8 6.22 4.28a.75.75 0 0 1 0-1.06Z"></path> </svg> </a> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Resources <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 d-lg-flex flex-wrap dropdown-menu-wide"> <div class="HeaderMenu-column px-lg-4 border-lg-right mb-4 mb-lg-0 pr-lg-7"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-topics-heading">Topics</span> <ul class="list-style-none f5" aria-labelledby="resources-topics-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ai","context":"resources","tag":"link","label":"ai_link_resources_navbar"}" href="/resources/articles/ai"> AI </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"devops","context":"resources","tag":"link","label":"devops_link_resources_navbar"}" href="/resources/articles/devops"> DevOps </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"security","context":"resources","tag":"link","label":"security_link_resources_navbar"}" href="/resources/articles/security"> Security </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"software_development","context":"resources","tag":"link","label":"software_development_link_resources_navbar"}" href="/resources/articles/software-development"> Software Development </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"view_all","context":"resources","tag":"link","label":"view_all_link_resources_navbar"}" href="/resources/articles"> View all </a></li> </ul> </div> </div> <div class="HeaderMenu-column px-lg-4"> <div class="border-bottom pb-3 pb-lg-0 border-lg-bottom-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="resources-explore-heading">Explore</span> <ul class="list-style-none f5" aria-labelledby="resources-explore-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"learning_pathways","context":"resources","tag":"link","label":"learning_pathways_link_resources_navbar"}" href="https://resources.github.com/learn/pathways"> Learning Pathways <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"events_amp_webinars","context":"resources","tag":"link","label":"events_amp_webinars_link_resources_navbar"}" href="https://resources.github.com"> Events & Webinars <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"ebooks_amp_whitepapers","context":"resources","tag":"link","label":"ebooks_amp_whitepapers_link_resources_navbar"}" href="https://github.com/resources/whitepapers"> Ebooks & Whitepapers </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"customer_stories","context":"resources","tag":"link","label":"customer_stories_link_resources_navbar"}" href="https://github.com/customer-stories"> Customer Stories </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary Link--external" target="_blank" data-analytics-event="{"location":"navbar","action":"partners","context":"resources","tag":"link","label":"partners_link_resources_navbar"}" href="https://partner.github.com"> Partners <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-link-external HeaderMenu-external-icon color-fg-subtle"> <path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path> </svg> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"executive_insights","context":"resources","tag":"link","label":"executive_insights_link_resources_navbar"}" href="https://github.com/solutions/executive-insights"> Executive Insights </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Open Source <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"github_sponsors","context":"open_source","tag":"link","label":"github_sponsors_link_open_source_navbar"}" href="/sponsors"> <div> <div class="color-fg-default h4">GitHub Sponsors</div> Fund open source developers </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"the_readme_project","context":"open_source","tag":"link","label":"the_readme_project_link_open_source_navbar"}" href="https://github.com/readme"> <div> <div class="color-fg-default h4">The ReadME Project</div> GitHub community articles </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="open-source-repositories-heading">Repositories</span> <ul class="list-style-none f5" aria-labelledby="open-source-repositories-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"topics","context":"open_source","tag":"link","label":"topics_link_open_source_navbar"}" href="https://github.com/topics"> Topics </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"trending","context":"open_source","tag":"link","label":"trending_link_open_source_navbar"}" href="https://github.com/trending"> Trending </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary" data-analytics-event="{"location":"navbar","action":"collections","context":"open_source","tag":"link","label":"collections_link_open_source_navbar"}" href="https://github.com/collections"> Collections </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <button type="button" class="HeaderMenu-link border-0 width-full width-lg-auto px-0 px-lg-2 py-lg-2 no-wrap d-flex flex-items-center flex-justify-between js-details-target" aria-expanded="false"> Enterprise <svg opacity="0.5" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-chevron-down HeaderMenu-icon ml-1"> <path d="M12.78 5.22a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06 0L3.22 6.28a.749.749 0 1 1 1.06-1.06L8 8.939l3.72-3.719a.749.749 0 0 1 1.06 0Z"></path> </svg> </button> <div class="HeaderMenu-dropdown dropdown-menu rounded m-0 p-0 pt-2 pt-lg-4 position-relative position-lg-absolute left-0 left-lg-n3 pb-2 pb-lg-4 px-lg-4"> <div class="HeaderMenu-column"> <div class="border-bottom pb-3 pb-lg-0 pb-lg-3 mb-3 mb-lg-0 mb-lg-3"> <ul class="list-style-none f5" > <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"enterprise_platform","context":"enterprise","tag":"link","label":"enterprise_platform_link_enterprise_navbar"}" href="/enterprise"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-stack color-fg-subtle mr-3"> <path d="M11.063 1.456a1.749 1.749 0 0 1 1.874 0l8.383 5.316a1.751 1.751 0 0 1 0 2.956l-8.383 5.316a1.749 1.749 0 0 1-1.874 0L2.68 9.728a1.751 1.751 0 0 1 0-2.956Zm1.071 1.267a.25.25 0 0 0-.268 0L3.483 8.039a.25.25 0 0 0 0 .422l8.383 5.316a.25.25 0 0 0 .268 0l8.383-5.316a.25.25 0 0 0 0-.422Z"></path><path d="M1.867 12.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path><path d="M1.867 16.324a.75.75 0 0 1 1.035-.232l8.964 5.685a.25.25 0 0 0 .268 0l8.964-5.685a.75.75 0 0 1 .804 1.267l-8.965 5.685a1.749 1.749 0 0 1-1.874 0l-8.965-5.685a.75.75 0 0 1-.231-1.035Z"></path> </svg> <div> <div class="color-fg-default h4">Enterprise platform</div> AI-powered developer platform </div> </a></li> </ul> </div> <div class="border-bottom pb-3 pb-lg-0 border-bottom-0"> <span class="d-block h4 color-fg-default my-1" id="enterprise-available-add-ons-heading">Available add-ons</span> <ul class="list-style-none f5" aria-labelledby="enterprise-available-add-ons-heading"> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"github_advanced_security","context":"enterprise","tag":"link","label":"github_advanced_security_link_enterprise_navbar"}" href="https://github.com/security/advanced-security"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-shield-check color-fg-subtle mr-3"> <path d="M16.53 9.78a.75.75 0 0 0-1.06-1.06L11 13.19l-1.97-1.97a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l5-5Z"></path><path d="m12.54.637 8.25 2.675A1.75 1.75 0 0 1 22 4.976V10c0 6.19-3.771 10.704-9.401 12.83a1.704 1.704 0 0 1-1.198 0C5.77 20.705 2 16.19 2 10V4.976c0-.758.489-1.43 1.21-1.664L11.46.637a1.748 1.748 0 0 1 1.08 0Zm-.617 1.426-8.25 2.676a.249.249 0 0 0-.173.237V10c0 5.46 3.28 9.483 8.43 11.426a.199.199 0 0 0 .14 0C17.22 19.483 20.5 15.461 20.5 10V4.976a.25.25 0 0 0-.173-.237l-8.25-2.676a.253.253 0 0 0-.154 0Z"></path> </svg> <div> <div class="color-fg-default h4">GitHub Advanced Security</div> Enterprise-grade security features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description pb-lg-3" data-analytics-event="{"location":"navbar","action":"copilot_for_business","context":"enterprise","tag":"link","label":"copilot_for_business_link_enterprise_navbar"}" href="/features/copilot/copilot-business"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-copilot color-fg-subtle mr-3"> <path d="M23.922 16.992c-.861 1.495-5.859 5.023-11.922 5.023-6.063 0-11.061-3.528-11.922-5.023A.641.641 0 0 1 0 16.736v-2.869a.841.841 0 0 1 .053-.22c.372-.935 1.347-2.292 2.605-2.656.167-.429.414-1.055.644-1.517a10.195 10.195 0 0 1-.052-1.086c0-1.331.282-2.499 1.132-3.368.397-.406.89-.717 1.474-.952 1.399-1.136 3.392-2.093 6.122-2.093 2.731 0 4.767.957 6.166 2.093.584.235 1.077.546 1.474.952.85.869 1.132 2.037 1.132 3.368 0 .368-.014.733-.052 1.086.23.462.477 1.088.644 1.517 1.258.364 2.233 1.721 2.605 2.656a.832.832 0 0 1 .053.22v2.869a.641.641 0 0 1-.078.256ZM12.172 11h-.344a4.323 4.323 0 0 1-.355.508C10.703 12.455 9.555 13 7.965 13c-1.725 0-2.989-.359-3.782-1.259a2.005 2.005 0 0 1-.085-.104L4 11.741v6.585c1.435.779 4.514 2.179 8 2.179 3.486 0 6.565-1.4 8-2.179v-6.585l-.098-.104s-.033.045-.085.104c-.793.9-2.057 1.259-3.782 1.259-1.59 0-2.738-.545-3.508-1.492a4.323 4.323 0 0 1-.355-.508h-.016.016Zm.641-2.935c.136 1.057.403 1.913.878 2.497.442.544 1.134.938 2.344.938 1.573 0 2.292-.337 2.657-.751.384-.435.558-1.15.558-2.361 0-1.14-.243-1.847-.705-2.319-.477-.488-1.319-.862-2.824-1.025-1.487-.161-2.192.138-2.533.529-.269.307-.437.808-.438 1.578v.021c0 .265.021.562.063.893Zm-1.626 0c.042-.331.063-.628.063-.894v-.02c-.001-.77-.169-1.271-.438-1.578-.341-.391-1.046-.69-2.533-.529-1.505.163-2.347.537-2.824 1.025-.462.472-.705 1.179-.705 2.319 0 1.211.175 1.926.558 2.361.365.414 1.084.751 2.657.751 1.21 0 1.902-.394 2.344-.938.475-.584.742-1.44.878-2.497Z"></path><path d="M14.5 14.25a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Zm-5 0a1 1 0 0 1 1 1v2a1 1 0 0 1-2 0v-2a1 1 0 0 1 1-1Z"></path> </svg> <div> <div class="color-fg-default h4">Copilot for business</div> Enterprise-grade AI features </div> </a></li> <li> <a class="HeaderMenu-dropdown-link d-block no-underline position-relative py-2 Link--secondary d-flex flex-items-center Link--has-description" data-analytics-event="{"location":"navbar","action":"premium_support","context":"enterprise","tag":"link","label":"premium_support_link_enterprise_navbar"}" href="/premium-support"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-comment-discussion color-fg-subtle mr-3"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 14.25 14H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 15.543V14H1.75A1.75 1.75 0 0 1 0 12.25v-9.5C0 1.784.784 1 1.75 1ZM1.5 2.75v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Z"></path><path d="M22.5 8.75a.25.25 0 0 0-.25-.25h-3.5a.75.75 0 0 1 0-1.5h3.5c.966 0 1.75.784 1.75 1.75v9.5A1.75 1.75 0 0 1 22.25 20H21v1.543a1.457 1.457 0 0 1-2.487 1.03L15.939 20H10.75A1.75 1.75 0 0 1 9 18.25v-1.465a.75.75 0 0 1 1.5 0v1.465c0 .138.112.25.25.25h5.5a.75.75 0 0 1 .53.22l2.72 2.72v-2.19a.75.75 0 0 1 .75-.75h2a.25.25 0 0 0 .25-.25v-9.5Z"></path> </svg> <div> <div class="color-fg-default h4">Premium Support</div> Enterprise-grade 24/7 support </div> </a></li> </ul> </div> </div> </div> </li> <li class="HeaderMenu-item position-relative flex-wrap flex-justify-between flex-items-center d-block d-lg-flex flex-lg-nowrap flex-lg-items-center js-details-container js-header-menu-item"> <a class="HeaderMenu-link no-underline px-0 px-lg-2 py-3 py-lg-2 d-block d-lg-inline-block" data-analytics-event="{"location":"navbar","action":"pricing","context":"global","tag":"link","label":"pricing_link_global_navbar"}" href="https://github.com/pricing">Pricing</a> </li> </ul> </nav> <div class="d-flex flex-column flex-lg-row width-full flex-justify-end flex-lg-items-center text-center mt-3 mt-lg-0 text-lg-left ml-lg-3"> <qbsearch-input class="search-input" data-scope="repo:younata/Nimble" data-custom-scopes-path="/search/custom_scopes" data-delete-custom-scopes-csrf="pSvfJL_mTGEM3WXdrf6eh017PpLAMSPf76Jy1DmpU_h7fL1bW9XhhMS_sn2_l6C0bdjYVnE3xQqdvSaEFQ9YTA" data-max-custom-scopes="10" data-header-redesign-enabled="false" data-initial-value="" data-blackbird-suggestions-path="/search/suggestions" data-jump-to-suggestions-path="/_graphql/GetSuggestedNavigationDestinations" data-current-repository="younata/Nimble" data-current-org="" data-current-owner="younata" data-logged-in="false" data-copilot-chat-enabled="false" data-nl-search-enabled="false" data-retain-scroll-position="true"> <div class="search-input-container search-with-dialog position-relative d-flex flex-row flex-items-center mr-4 rounded" data-action="click:qbsearch-input#searchInputContainerClicked" > <button type="button" class="header-search-button placeholder input-button form-control d-flex flex-1 flex-self-stretch flex-items-center no-wrap width-full py-0 pl-2 pr-0 text-left border-0 box-shadow-none" data-target="qbsearch-input.inputButton" aria-label="Search or jump to…" aria-haspopup="dialog" placeholder="Search or jump to..." data-hotkey=s,/ autocapitalize="off" data-analytics-event="{"location":"navbar","action":"searchbar","context":"global","tag":"input","label":"searchbar_input_global_navbar"}" data-action="click:qbsearch-input#handleExpand" > <div class="mr-2 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </div> <span class="flex-1" data-target="qbsearch-input.inputButtonText">Search or jump to...</span> <div class="d-flex" data-target="qbsearch-input.hotkeyIndicator"> <svg xmlns="http://www.w3.org/2000/svg" width="22" height="20" aria-hidden="true" class="mr-1"><path fill="none" stroke="#979A9C" opacity=".4" d="M3.5.5h12c1.7 0 3 1.3 3 3v13c0 1.7-1.3 3-3 3h-12c-1.7 0-3-1.3-3-3v-13c0-1.7 1.3-3 3-3z"></path><path fill="#979A9C" d="M11.8 6L8 15.1h-.9L10.8 6h1z"></path></svg> </div> </button> <input type="hidden" name="type" class="js-site-search-type-field"> <div class="Overlay--hidden " data-modal-dialog-overlay> <modal-dialog data-action="close:qbsearch-input#handleClose cancel:qbsearch-input#handleClose" data-target="qbsearch-input.searchSuggestionsDialog" role="dialog" id="search-suggestions-dialog" aria-modal="true" aria-labelledby="search-suggestions-dialog-header" data-view-component="true" class="Overlay Overlay--width-large Overlay--height-auto"> <h1 id="search-suggestions-dialog-header" class="sr-only">Search code, repositories, users, issues, pull requests...</h1> <div class="Overlay-body Overlay-body--paddingNone"> <div data-view-component="true"> <div class="search-suggestions position-fixed width-full color-shadow-large border color-fg-default color-bg-default overflow-hidden d-flex flex-column query-builder-container" style="border-radius: 12px;" data-target="qbsearch-input.queryBuilderContainer" hidden > <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="query-builder-test-form" action="" accept-charset="UTF-8" method="get"> <query-builder data-target="qbsearch-input.queryBuilder" id="query-builder-query-builder-test" data-filter-key=":" data-view-component="true" class="QueryBuilder search-query-builder"> <div class="FormControl FormControl--fullWidth"> <label id="query-builder-test-label" for="query-builder-test" class="FormControl-label sr-only"> Search </label> <div class="QueryBuilder-StyledInput width-fit " data-target="query-builder.styledInput" > <span id="query-builder-test-leadingvisual-wrap" class="FormControl-input-leadingVisualWrap QueryBuilder-leadingVisualWrap"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search FormControl-input-leadingVisual"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </span> <div data-target="query-builder.styledInputContainer" class="QueryBuilder-StyledInputContainer"> <div aria-hidden="true" class="QueryBuilder-StyledInputContent" data-target="query-builder.styledInputContent" ></div> <div class="QueryBuilder-InputWrapper"> <div aria-hidden="true" class="QueryBuilder-Sizer" data-target="query-builder.sizer"></div> <input id="query-builder-test" name="query-builder-test" value="" autocomplete="off" type="text" role="combobox" spellcheck="false" aria-expanded="false" aria-describedby="validation-155d3354-b42f-4d2f-a2c5-4aea5615f092" data-target="query-builder.input" data-action=" input:query-builder#inputChange blur:query-builder#inputBlur keydown:query-builder#inputKeydown focus:query-builder#inputFocus " data-view-component="true" class="FormControl-input QueryBuilder-Input FormControl-medium" /> </div> </div> <span class="sr-only" id="query-builder-test-clear">Clear</span> <button role="button" id="query-builder-test-clear-button" aria-labelledby="query-builder-test-clear query-builder-test-label" data-target="query-builder.clearButton" data-action=" click:query-builder#clear focus:query-builder#clearButtonFocus blur:query-builder#clearButtonBlur " variant="small" hidden="hidden" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium mr-1 px-2 py-0 d-flex flex-items-center rounded-1 color-fg-muted"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x-circle-fill Button-visual"> <path d="M2.343 13.657A8 8 0 1 1 13.658 2.343 8 8 0 0 1 2.343 13.657ZM6.03 4.97a.751.751 0 0 0-1.042.018.751.751 0 0 0-.018 1.042L6.94 8 4.97 9.97a.749.749 0 0 0 .326 1.275.749.749 0 0 0 .734-.215L8 9.06l1.97 1.97a.749.749 0 0 0 1.275-.326.749.749 0 0 0-.215-.734L9.06 8l1.97-1.97a.749.749 0 0 0-.326-1.275.749.749 0 0 0-.734.215L8 6.94Z"></path> </svg> </button> </div> <template id="search-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-search"> <path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path> </svg> </template> <template id="code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="file-code-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-file-code"> <path d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0 1 14.25 15h-9a.75.75 0 0 1 0-1.5h9a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 10 4.25V1.5H5.75a.25.25 0 0 0-.25.25v2.5a.75.75 0 0 1-1.5 0Zm1.72 4.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734l1.47-1.47-1.47-1.47a.75.75 0 0 1 0-1.06ZM3.28 7.78 1.81 9.25l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Zm8.22-6.218V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path> </svg> </template> <template id="history-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-history"> <path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path> </svg> </template> <template id="repo-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo"> <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path> </svg> </template> <template id="bookmark-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bookmark"> <path d="M3 2.75C3 1.784 3.784 1 4.75 1h6.5c.966 0 1.75.784 1.75 1.75v11.5a.75.75 0 0 1-1.227.579L8 11.722l-3.773 3.107A.751.751 0 0 1 3 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.91l3.023-2.489a.75.75 0 0 1 .954 0l3.023 2.49V2.75a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="plus-circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-plus-circle"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm7.25-3.25v2.5h2.5a.75.75 0 0 1 0 1.5h-2.5v2.5a.75.75 0 0 1-1.5 0v-2.5h-2.5a.75.75 0 0 1 0-1.5h2.5v-2.5a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="circle-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> </template> <template id="trash-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-trash"> <path d="M11 1.75V3h2.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H5V1.75C5 .784 5.784 0 6.75 0h2.5C10.216 0 11 .784 11 1.75ZM4.496 6.675l.66 6.6a.25.25 0 0 0 .249.225h5.19a.25.25 0 0 0 .249-.225l.66-6.6a.75.75 0 0 1 1.492.149l-.66 6.6A1.748 1.748 0 0 1 10.595 15h-5.19a1.75 1.75 0 0 1-1.741-1.575l-.66-6.6a.75.75 0 1 1 1.492-.15ZM6.5 1.75V3h3V1.75a.25.25 0 0 0-.25-.25h-2.5a.25.25 0 0 0-.25.25Z"></path> </svg> </template> <template id="team-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-people"> <path d="M2 5.5a3.5 3.5 0 1 1 5.898 2.549 5.508 5.508 0 0 1 3.034 4.084.75.75 0 1 1-1.482.235 4 4 0 0 0-7.9 0 .75.75 0 0 1-1.482-.236A5.507 5.507 0 0 1 3.102 8.05 3.493 3.493 0 0 1 2 5.5ZM11 4a3.001 3.001 0 0 1 2.22 5.018 5.01 5.01 0 0 1 2.56 3.012.749.749 0 0 1-.885.954.752.752 0 0 1-.549-.514 3.507 3.507 0 0 0-2.522-2.372.75.75 0 0 1-.574-.73v-.352a.75.75 0 0 1 .416-.672A1.5 1.5 0 0 0 11 5.5.75.75 0 0 1 11 4Zm-5.5-.5a2 2 0 1 0-.001 3.999A2 2 0 0 0 5.5 3.5Z"></path> </svg> </template> <template id="project-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-project"> <path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25ZM11.75 3a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-1.5 0v-7.5a.75.75 0 0 1 .75-.75Zm-8.25.75a.75.75 0 0 1 1.5 0v5.5a.75.75 0 0 1-1.5 0ZM8 3a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 3Z"></path> </svg> </template> <template id="pencil-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pencil"> <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z"></path> </svg> </template> <template id="copilot-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot"> <path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path> </svg> </template> <template id="copilot-error-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copilot-error"> <path d="M16 11.24c0 .112-.072.274-.21.467L13 9.688V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-.198 0-.388-.009-.571-.029L6.833 5.226a4.01 4.01 0 0 0 .17-.782c.117-.935-.037-1.395-.241-1.614-.193-.206-.637-.413-1.682-.297-.683.076-1.115.231-1.395.415l-1.257-.91c.579-.564 1.413-.877 2.485-.996 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095Zm-5.083-8.707c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Zm2.511 11.074c-1.393.776-3.272 1.428-5.43 1.428-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.18-.455-.241-.963-.252-1.475L.31 4.107A.747.747 0 0 1 0 3.509V3.49a.748.748 0 0 1 .625-.73c.156-.026.306.047.435.139l14.667 10.578a.592.592 0 0 1 .227.264.752.752 0 0 1 .046.249v.022a.75.75 0 0 1-1.19.596Zm-1.367-.991L5.635 7.964a5.128 5.128 0 0 1-.889.073c-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433 1.539 0 3.089-.505 4.063-.934Z"></path> </svg> </template> <template id="workflow-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-workflow"> <path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="book-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> </template> <template id="code-review-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-review"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 13H8.061l-2.574 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25v-8.5C0 1.784.784 1 1.75 1ZM1.5 2.75v8.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-8.5a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm5.28 1.72a.75.75 0 0 1 0 1.06L5.31 7l1.47 1.47a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018l-2-2a.75.75 0 0 1 0-1.06l2-2a.75.75 0 0 1 1.06 0Zm2.44 0a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L10.69 7 9.22 5.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </template> <template id="codespaces-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-codespaces"> <path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path> </svg> </template> <template id="comment-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment"> <path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> </template> <template id="comment-discussion-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-comment-discussion"> <path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path> </svg> </template> <template id="organization-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-organization"> <path d="M1.75 16A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0h8.5C11.216 0 12 .784 12 1.75v12.5c0 .085-.006.168-.018.25h2.268a.25.25 0 0 0 .25-.25V8.285a.25.25 0 0 0-.111-.208l-1.055-.703a.749.749 0 1 1 .832-1.248l1.055.703c.487.325.779.871.779 1.456v5.965A1.75 1.75 0 0 1 14.25 16h-3.5a.766.766 0 0 1-.197-.026c-.099.017-.2.026-.303.026h-3a.75.75 0 0 1-.75-.75V14h-1v1.25a.75.75 0 0 1-.75.75Zm-.25-1.75c0 .138.112.25.25.25H4v-1.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 .75.75v1.25h2.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM3.75 6h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 3.75A.75.75 0 0 1 3.75 3h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 3.75Zm4 3A.75.75 0 0 1 7.75 6h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 7 6.75ZM7.75 3h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5ZM3 9.75A.75.75 0 0 1 3.75 9h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 9.75ZM7.75 9h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="rocket-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-rocket"> <path d="M14.064 0h.186C15.216 0 16 .784 16 1.75v.186a8.752 8.752 0 0 1-2.564 6.186l-.458.459c-.314.314-.641.616-.979.904v3.207c0 .608-.315 1.172-.833 1.49l-2.774 1.707a.749.749 0 0 1-1.11-.418l-.954-3.102a1.214 1.214 0 0 1-.145-.125L3.754 9.816a1.218 1.218 0 0 1-.124-.145L.528 8.717a.749.749 0 0 1-.418-1.11l1.71-2.774A1.748 1.748 0 0 1 3.31 4h3.204c.288-.338.59-.665.904-.979l.459-.458A8.749 8.749 0 0 1 14.064 0ZM8.938 3.623h-.002l-.458.458c-.76.76-1.437 1.598-2.02 2.5l-1.5 2.317 2.143 2.143 2.317-1.5c.902-.583 1.74-1.26 2.499-2.02l.459-.458a7.25 7.25 0 0 0 2.123-5.127V1.75a.25.25 0 0 0-.25-.25h-.186a7.249 7.249 0 0 0-5.125 2.123ZM3.56 14.56c-.732.732-2.334 1.045-3.005 1.148a.234.234 0 0 1-.201-.064.234.234 0 0 1-.064-.201c.103-.671.416-2.273 1.15-3.003a1.502 1.502 0 1 1 2.12 2.12Zm6.94-3.935c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 0 0 .119-.213ZM3.678 8.116 5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 0 0-.213.119l-1.2 1.95ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </template> <template id="shield-check-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield-check"> <path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="heart-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-heart"> <path d="m8 14.25.345.666a.75.75 0 0 1-.69 0l-.008-.004-.018-.01a7.152 7.152 0 0 1-.31-.17 22.055 22.055 0 0 1-3.434-2.414C2.045 10.731 0 8.35 0 5.5 0 2.836 2.086 1 4.25 1 5.797 1 7.153 1.802 8 3.02 8.847 1.802 10.203 1 11.75 1 13.914 1 16 2.836 16 5.5c0 2.85-2.045 5.231-3.885 6.818a22.066 22.066 0 0 1-3.744 2.584l-.018.01-.006.003h-.002ZM4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.58 20.58 0 0 0 8 13.393a20.58 20.58 0 0 0 3.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 0 1-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5Z"></path> </svg> </template> <template id="server-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-server"> <path d="M1.75 1h12.5c.966 0 1.75.784 1.75 1.75v4c0 .372-.116.717-.314 1 .198.283.314.628.314 1v4a1.75 1.75 0 0 1-1.75 1.75H1.75A1.75 1.75 0 0 1 0 12.75v-4c0-.358.109-.707.314-1a1.739 1.739 0 0 1-.314-1v-4C0 1.784.784 1 1.75 1ZM1.5 2.75v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25Zm.25 5.75a.25.25 0 0 0-.25.25v4c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-4a.25.25 0 0 0-.25-.25ZM7 4.75A.75.75 0 0 1 7.75 4h4.5a.75.75 0 0 1 0 1.5h-4.5A.75.75 0 0 1 7 4.75ZM7.75 10h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM3 4.75A.75.75 0 0 1 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5A.75.75 0 0 1 3 4.75ZM3.75 10h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1 0-1.5Z"></path> </svg> </template> <template id="globe-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-globe"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM5.78 8.75a9.64 9.64 0 0 0 1.363 4.177c.255.426.542.832.857 1.215.245-.296.551-.705.857-1.215A9.64 9.64 0 0 0 10.22 8.75Zm4.44-1.5a9.64 9.64 0 0 0-1.363-4.177c-.307-.51-.612-.919-.857-1.215a9.927 9.927 0 0 0-.857 1.215A9.64 9.64 0 0 0 5.78 7.25Zm-5.944 1.5H1.543a6.507 6.507 0 0 0 4.666 5.5c-.123-.181-.24-.365-.352-.552-.715-1.192-1.437-2.874-1.581-4.948Zm-2.733-1.5h2.733c.144-2.074.866-3.756 1.58-4.948.12-.197.237-.381.353-.552a6.507 6.507 0 0 0-4.666 5.5Zm10.181 1.5c-.144 2.074-.866 3.756-1.58 4.948-.12.197-.237.381-.353.552a6.507 6.507 0 0 0 4.666-5.5Zm2.733-1.5a6.507 6.507 0 0 0-4.666-5.5c.123.181.24.365.353.552.714 1.192 1.436 2.874 1.58 4.948Z"></path> </svg> </template> <template id="issue-opened-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-issue-opened"> <path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path> </svg> </template> <template id="device-mobile-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-mobile"> <path d="M3.75 0h8.5C13.216 0 14 .784 14 1.75v12.5A1.75 1.75 0 0 1 12.25 16h-8.5A1.75 1.75 0 0 1 2 14.25V1.75C2 .784 2.784 0 3.75 0ZM3.5 1.75v12.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25ZM8 13a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path> </svg> </template> <template id="package-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-package"> <path d="m8.878.392 5.25 3.045c.54.314.872.89.872 1.514v6.098a1.75 1.75 0 0 1-.872 1.514l-5.25 3.045a1.75 1.75 0 0 1-1.756 0l-5.25-3.045A1.75 1.75 0 0 1 1 11.049V4.951c0-.624.332-1.201.872-1.514L7.122.392a1.75 1.75 0 0 1 1.756 0ZM7.875 1.69l-4.63 2.685L8 7.133l4.755-2.758-4.63-2.685a.248.248 0 0 0-.25 0ZM2.5 5.677v5.372c0 .09.047.171.125.216l4.625 2.683V8.432Zm6.25 8.271 4.625-2.683a.25.25 0 0 0 .125-.216V5.677L8.75 8.432Z"></path> </svg> </template> <template id="credit-card-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-credit-card"> <path d="M10.75 9a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z"></path><path d="M0 3.75C0 2.784.784 2 1.75 2h12.5c.966 0 1.75.784 1.75 1.75v8.5A1.75 1.75 0 0 1 14.25 14H1.75A1.75 1.75 0 0 1 0 12.25ZM14.5 6.5h-13v5.75c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25Zm0-2.75a.25.25 0 0 0-.25-.25H1.75a.25.25 0 0 0-.25.25V5h13Z"></path> </svg> </template> <template id="play-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </template> <template id="gift-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-gift"> <path d="M2 2.75A2.75 2.75 0 0 1 4.75 0c.983 0 1.873.42 2.57 1.232.268.318.497.668.68 1.042.183-.375.411-.725.68-1.044C9.376.42 10.266 0 11.25 0a2.75 2.75 0 0 1 2.45 4h.55c.966 0 1.75.784 1.75 1.75v2c0 .698-.409 1.301-1 1.582v4.918A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25V9.332C.409 9.05 0 8.448 0 7.75v-2C0 4.784.784 4 1.75 4h.55c-.192-.375-.3-.8-.3-1.25ZM7.25 9.5H2.5v4.75c0 .138.112.25.25.25h4.5Zm1.5 0v5h4.5a.25.25 0 0 0 .25-.25V9.5Zm0-4V8h5.5a.25.25 0 0 0 .25-.25v-2a.25.25 0 0 0-.25-.25Zm-7 0a.25.25 0 0 0-.25.25v2c0 .138.112.25.25.25h5.5V5.5h-5.5Zm3-4a1.25 1.25 0 0 0 0 2.5h2.309c-.233-.818-.542-1.401-.878-1.793-.43-.502-.915-.707-1.431-.707ZM8.941 4h2.309a1.25 1.25 0 0 0 0-2.5c-.516 0-1 .205-1.43.707-.337.392-.646.975-.879 1.793Z"></path> </svg> </template> <template id="code-square-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-square"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </template> <template id="device-desktop-icon"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-device-desktop"> <path d="M14.25 1c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.752.752 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5C0 1.784.784 1 1.75 1ZM1.75 2.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25ZM9.018 12H6.982a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5Z"></path> </svg> </template> <div class="position-relative"> <ul role="listbox" class="ActionListWrap QueryBuilder-ListWrap" aria-label="Suggestions" data-action=" combobox-commit:query-builder#comboboxCommit mousedown:query-builder#resultsMousedown " data-target="query-builder.resultsList" data-persist-list=false id="query-builder-test-results" ></ul> </div> <div class="FormControl-inlineValidation" id="validation-155d3354-b42f-4d2f-a2c5-4aea5615f092" hidden="hidden"> <span class="FormControl-inlineValidation--visual"> <svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg> </span> <span></span> </div> </div> <div data-target="query-builder.screenReaderFeedback" aria-live="polite" aria-atomic="true" class="sr-only"></div> </query-builder></form> <div class="d-flex flex-row color-fg-muted px-3 text-small color-bg-default search-feedback-prompt"> <a target="_blank" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax" data-view-component="true" class="Link color-fg-accent text-normal ml-2">Search syntax tips</a> <div class="d-flex flex-1"></div> </div> </div> </div> </div> </modal-dialog></div> </div> <div data-action="click:qbsearch-input#retract" class="dark-backdrop position-fixed" hidden data-target="qbsearch-input.darkBackdrop"></div> <div class="color-fg-default"> <dialog-helper> <dialog data-target="qbsearch-input.feedbackDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="feedback-dialog" aria-modal="true" aria-labelledby="feedback-dialog-title" aria-describedby="feedback-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="feedback-dialog-title"> Provide feedback </h1> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="feedback-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="feedback-dialog-title"> <div data-view-component="true" class="Overlay-body"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="code-search-feedback-form" data-turbo="false" action="/search/feedback" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="0GA1FJm+d8WJ0y8GD6p2v2OECzxa3XKemYiJ4Z4HswXpoJy7Qn85MuQ3Ha7nCJPLwOnb8+Bx6/X4q+uY5kWPng==" /> <p>We read every piece of feedback, and take your input very seriously.</p> <textarea name="feedback" class="form-control width-full mb-2" style="height: 120px" id="feedback"></textarea> <input name="include_email" id="include_email" aria-label="Include my email address so I can be contacted" class="form-control mr-2" type="checkbox"> <label for="include_email" style="font-weight: normal">Include my email address so I can be contacted</label> </form></div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd"> <button data-close-dialog-id="feedback-dialog" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="code-search-feedback-form" data-action="click:qbsearch-input#submitFeedback" type="submit" data-view-component="true" class="btn-primary btn"> Submit feedback </button> </div> </dialog></dialog-helper> <custom-scopes data-target="qbsearch-input.customScopesManager"> <dialog-helper> <dialog data-target="custom-scopes.customScopesModalDialog" data-action="close:qbsearch-input#handleDialogClose cancel:qbsearch-input#handleDialogClose" id="custom-scopes-dialog" aria-modal="true" aria-labelledby="custom-scopes-dialog-title" aria-describedby="custom-scopes-dialog-description" data-view-component="true" class="Overlay Overlay-whenNarrow Overlay--size-medium Overlay--motion-scaleFade Overlay--disableScroll"> <div data-view-component="true" class="Overlay-header Overlay-header--divided"> <div class="Overlay-headerContentWrap"> <div class="Overlay-titleWrap"> <h1 class="Overlay-title " id="custom-scopes-dialog-title"> Saved searches </h1> <h2 id="custom-scopes-dialog-description" class="Overlay-description">Use saved searches to filter your results more quickly</h2> </div> <div class="Overlay-actionWrap"> <button data-close-dialog-id="custom-scopes-dialog" aria-label="Close" type="button" data-view-component="true" class="close-button Overlay-closeButton"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg></button> </div> </div> </div> <scrollable-region data-labelled-by="custom-scopes-dialog-title"> <div data-view-component="true" class="Overlay-body"> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <div hidden class="create-custom-scope-form" data-target="custom-scopes.createCustomScopeForm"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form id="custom-scopes-dialog-form" data-turbo="false" action="/search/custom_scopes" accept-charset="UTF-8" method="post"><input type="hidden" data-csrf="true" name="authenticity_token" value="7nldIoZAoKqy3hstmFqg3eyaE8+iSHKtRyZel6vQE6RKZJHCICfUHo5JjEHW3CPNFVCYUB3QyswaAx8BpKQ2gw==" /> <div data-target="custom-scopes.customScopesModalDialogFlash"></div> <input type="hidden" id="custom_scope_id" name="custom_scope_id" data-target="custom-scopes.customScopesIdField"> <div class="form-group"> <label for="custom_scope_name">Name</label> <auto-check src="/search/custom_scopes/check_name" required only-validate-on-blur="false"> <input type="text" name="custom_scope_name" id="custom_scope_name" data-target="custom-scopes.customScopesNameField" class="form-control" autocomplete="off" placeholder="github-ruby" required maxlength="50"> <input type="hidden" data-csrf="true" value="Fx9Wf808+4AsbqeZ+Ho7iJ+JBdsIzc9J9nZEwViwxjGXgvxIP/BC0knpkRGzal/7BF3QT7lE7qmMAgvU5FDD/Q==" /> </auto-check> </div> <div class="form-group"> <label for="custom_scope_query">Query</label> <input type="text" name="custom_scope_query" id="custom_scope_query" data-target="custom-scopes.customScopesQueryField" class="form-control" autocomplete="off" placeholder="(repo:mona/a OR repo:mona/b) AND lang:python" required maxlength="500"> </div> <p class="text-small color-fg-muted"> To see all available qualifiers, see our <a class="Link--inTextBlock" href="https://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax">documentation</a>. </p> </form> </div> <div data-target="custom-scopes.manageCustomScopesForm"> <div data-target="custom-scopes.list"></div> </div> </div> </scrollable-region> <div data-view-component="true" class="Overlay-footer Overlay-footer--alignEnd Overlay-footer--divided"> <button data-action="click:custom-scopes#customScopesCancel" type="button" data-view-component="true" class="btn"> Cancel </button> <button form="custom-scopes-dialog-form" data-action="click:custom-scopes#customScopesSubmit" data-target="custom-scopes.customScopesSubmitButton" type="submit" data-view-component="true" class="btn-primary btn"> Create saved search </button> </div> </dialog></dialog-helper> </custom-scopes> </div> </qbsearch-input> <div class="position-relative HeaderMenu-link-wrap d-lg-inline-block"> <a href="/login?return_to=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble" class="HeaderMenu-link HeaderMenu-link--sign-in HeaderMenu-button flex-shrink-0 no-underline d-none d-lg-inline-flex border border-lg-0 rounded rounded-lg-0 px-2 py-1" style="margin-left: 12px;" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="845b297be0a842bc5ed4e17f1f9d3c15aa1e94f35cb220b32b22e903f0891c74" data-analytics-event="{"category":"Marketing nav","action":"click to go to homepage","label":"ref_page:Marketing;ref_cta:Sign in;ref_loc:Header"}" > Sign in </a> </div> <a href="/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E&source=header-repo&source_repo=younata%2FNimble" class="HeaderMenu-link HeaderMenu-link--sign-up HeaderMenu-button flex-shrink-0 d-flex d-lg-inline-flex no-underline border color-border-default rounded px-2 py-1" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"site header menu","repository_id":null,"auth_type":"SIGN_UP","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="845b297be0a842bc5ed4e17f1f9d3c15aa1e94f35cb220b32b22e903f0891c74" data-analytics-event="{"category":"Sign up","action":"click to sign up for account","label":"ref_page:/<user-name>/<repo-name>;ref_cta:Sign up;ref_loc:header logged out"}" > Sign up </a> <button type="button" class="sr-only js-header-menu-focus-trap d-block d-lg-none">Reseting focus</button> </div> </div> </div> </div> </header> <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <button id="icon-button-6bdea601-a122-4038-b5de-1da62871731b" aria-labelledby="tooltip-5e0b3496-5b5d-48d5-b98b-fba6206f662c" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button><tool-tip id="tooltip-5e0b3496-5b5d-48d5-b98b-fba6206f662c" for="icon-button-6bdea601-a122-4038-b5de-1da62871731b" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip> </div> </div> <div id="start-of-content" class="show-on-focus"></div> <div id="js-flash-container" class="flash-container" data-turbo-replace> <template class="js-flash-template"> <div class="flash flash-full {{ className }}"> <div > <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div aria-atomic="true" role="alert" class="js-flash-alert"> <div>{{ message }}</div> </div> </div> </div> </template> </div> <div class="application-main " data-commit-hovercards-enabled data-discussion-hovercards-enabled data-issue-and-pr-hovercards-enabled data-project-hovercards-enabled > <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class=""> <main id="js-repo-pjax-container" > <div id="repository-container-header" class="pt-3 hide-full-screen" style="background-color: var(--page-header-bgColor, var(--color-page-header-bg));" data-turbo-replace> <div class="d-flex flex-nowrap flex-justify-end mb-3 px-3 px-lg-5" style="gap: 1rem;"> <div class="flex-auto min-width-0 width-fit"> <div class=" d-flex flex-wrap flex-items-center wb-break-word f3 text-normal"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked color-fg-muted mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <span class="author flex-self-stretch" itemprop="author"> <a class="url fn" rel="author" data-hovercard-type="user" data-hovercard-url="/users/younata/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/younata"> younata </a> </span> <span class="mx-1 flex-self-stretch color-fg-muted">/</span> <strong itemprop="name" class="mr-2 flex-self-stretch"> <a data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/younata/Nimble">Nimble</a> </strong> <span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span> </div> <span class="text-small lh-condensed-ultra no-wrap mt-1" data-repository-hovercards-enabled> forked from <a data-hovercard-type="repository" data-hovercard-url="/Quick/Nimble/hovercard" class="Link--inTextBlock" href="/Quick/Nimble">Quick/Nimble</a> </span> </div> <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;"> <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;"> <li> <a href="/login?return_to=%2Fyounata%2FNimble" rel="nofollow" id="repository-details-watch-button" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"notification subscription menu watch","repository_id":null,"auth_type":"LOG_IN","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="001ea2ee818c26aa4ff234e68e1aa0ecfaec5149c91869a83288a4fa885801fe" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-26d3fab9-8e84-40b3-899d-278278d46974" for="repository-details-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </li> <li> <a icon="repo-forked" id="fork-button" href="/login?return_to=%2Fyounata%2FNimble" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"repo details fork button","repository_id":338929302,"auth_type":"LOG_IN","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="5d79aa5e893f64b9e7b85446cdcb7d04ac5e70d0fc94bcbfa7b66c801b8338fb" data-view-component="true" class="btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg>Fork <span id="repo-network-counter" data-pjax-replace="true" data-turbo-replace="true" title="0" data-view-component="true" class="Counter">0</span> </a> </li> <li> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Fyounata%2FNimble" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"star button","repository_id":338929302,"auth_type":"LOG_IN","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="fa6f968a96f50947760944d69510b5425671ed145afa761253f5a2e4aaeb1c82" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> <span id="repo-stars-counter-star" aria-label="0 users starred this repository" data-singular-suffix="user starred this repository" data-plural-suffix="users starred this repository" data-turbo-replace="true" title="0" data-view-component="true" class="Counter js-social-count">0</span> </a></div> </li> </ul> </div> </div> <div id="responsive-meta-container" data-turbo-replace> <div class="d-block d-md-none mb-2 px-3 px-md-4 px-lg-5"> <p class="f4 mb-3 "> A Matcher Framework for Swift and Objective-C </p> <h3 class="sr-only">License</h3> <div class="mb-2"> <a href="/younata/Nimble/blob/main/LICENSE" class="Link--muted" data-analytics-event="{"category":"Repository Overview","action":"click","label":"location:sidebar;file:license"}" > <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-law mr-2"> <path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path> </svg> Apache-2.0 license </a> </div> <div class="mb-3"> <a class="Link--secondary no-underline mr-3" href="/younata/Nimble/stargazers"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-1"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <span class="text-bold">0</span> stars </a> <a class="Link--secondary no-underline mr-3" href="/younata/Nimble/forks"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-1"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <span class="text-bold">603</span> forks </a> <a class="Link--secondary no-underline mr-3 d-inline-block" href="/younata/Nimble/branches"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-branch mr-1"> <path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path> </svg> <span>Branches</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/younata/Nimble/tags"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-tag mr-1"> <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path> </svg> <span>Tags</span> </a> <a class="Link--secondary no-underline d-inline-block" href="/younata/Nimble/activity"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-1"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span>Activity</span> </a> </div> <div class="d-flex flex-wrap gap-2"> <div class="flex-1"> <div data-view-component="true" class="BtnGroup d-flex"> <a href="/login?return_to=%2Fyounata%2FNimble" rel="nofollow" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"star button","repository_id":338929302,"auth_type":"LOG_IN","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="fa6f968a96f50947760944d69510b5425671ed145afa761253f5a2e4aaeb1c82" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg><span data-view-component="true" class="d-inline"> Star </span> </a></div> </div> <div class="flex-1"> <a href="/login?return_to=%2Fyounata%2FNimble" rel="nofollow" id="files-overview-watch-button" data-hydro-click="{"event_type":"authentication.click","payload":{"location_in_page":"notification subscription menu watch","repository_id":null,"auth_type":"LOG_IN","originating_url":"https://github.com/younata/Nimble","user_id":null}}" data-hydro-click-hmac="001ea2ee818c26aa4ff234e68e1aa0ecfaec5149c91869a83288a4fa885801fe" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn btn-block"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2"> <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path> </svg>Notifications </a> <tool-tip id="tooltip-bc63c4e4-748e-48c4-8572-d15bb47596c9" for="files-overview-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip> </div> <span> </span> </div> </div> </div> <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 px-md-4 px-lg-5"> <ul data-view-component="true" class="UnderlineNav-body list-style-none"> <li data-view-component="true" class="d-inline-flex"> <a id="code-tab" href="/younata/Nimble" data-tab-item="i0code-tab" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches repo_packages repo_deployments repo_attestations /younata/Nimble" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g c" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Code","target":"UNDERLINE_NAV.TAB"}" aria-current="page" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item selected"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon d-none d-sm-inline"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> <span data-content="Code">Code</span> <span id="code-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="pull-requests-tab" href="/younata/Nimble/pulls" data-tab-item="i1pull-requests-tab" data-selected-links="repo_pulls checks /younata/Nimble/pulls" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g p" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Pull requests","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> <span data-content="Pull requests">Pull requests</span> <span id="pull-requests-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="actions-tab" href="/younata/Nimble/actions" data-tab-item="i2actions-tab" data-selected-links="repo_actions /younata/Nimble/actions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g a" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Actions","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play UnderlineNav-octicon d-none d-sm-inline"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> <span data-content="Actions">Actions</span> <span id="actions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="projects-tab" href="/younata/Nimble/projects" data-tab-item="i3projects-tab" data-selected-links="repo_projects new_repo_project repo_project /younata/Nimble/projects" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g b" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Projects","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table UnderlineNav-octicon d-none d-sm-inline"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> <span data-content="Projects">Projects</span> <span id="projects-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="security-tab" href="/younata/Nimble/security" data-tab-item="i4security-tab" data-selected-links="security overview alerts policy token_scanning code_scanning /younata/Nimble/security" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g s" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Security","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield UnderlineNav-octicon d-none d-sm-inline"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span data-content="Security">Security</span> <include-fragment src="/younata/Nimble/security/overall-count" accept="text/fragment+html"></include-fragment> </a></li> <li data-view-component="true" class="d-inline-flex"> <a id="insights-tab" href="/younata/Nimble/pulse" data-tab-item="i5insights-tab" data-selected-links="repo_graphs repo_contributors dependency_graph dependabot_updates pulse people community /younata/Nimble/pulse" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-analytics-event="{"category":"Underline navbar","action":"Click tab","label":"Insights","target":"UNDERLINE_NAV.TAB"}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph UnderlineNav-octicon d-none d-sm-inline"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> <span data-content="Insights">Insights</span> <span id="insights-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span> </a></li> </ul> <div style="visibility:hidden;" data-view-component="true" class="UnderlineNav-actions js-responsive-underlinenav-overflow position-absolute pr-3 pr-md-4 pr-lg-5 right-0"> <action-menu data-select-variant="none" data-view-component="true"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-button" popovertarget="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-overlay" aria-controls="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-list" aria-haspopup="true" aria-labelledby="tooltip-9e3c442b-04c8-48d5-8e60-1f3b37981ed6" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--medium UnderlineNav-item"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg> </button><tool-tip id="tooltip-9e3c442b-04c8-48d5-8e60-1f3b37981ed6" for="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Additional navigation options</tool-tip> <anchored-position data-target="action-menu.overlay" id="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-overlay" anchor="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-button" id="action-menu-2ef2ca03-b70c-46f1-971f-aafe185575ee-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li hidden="hidden" data-menu-item="i0code-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-441d442e-e31e-4ddc-a69c-b2f547012b07" href="/younata/Nimble" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Code </span> </a> </li> <li hidden="hidden" data-menu-item="i1pull-requests-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-b97f9752-a146-4833-abd9-40e66cf06c51" href="/younata/Nimble/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request"> <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Pull requests </span> </a> </li> <li hidden="hidden" data-menu-item="i2actions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-9bf3aa41-4cdd-4d36-a3fe-065ade22d390" href="/younata/Nimble/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play"> <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Actions </span> </a> </li> <li hidden="hidden" data-menu-item="i3projects-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-f8a98267-8dc5-4aaf-ae66-8086726af98d" href="/younata/Nimble/projects" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Projects </span> </a> </li> <li hidden="hidden" data-menu-item="i4security-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-78d6d49a-7b70-4055-bf02-0a531936e1e4" href="/younata/Nimble/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield"> <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Security </span> </a> </li> <li hidden="hidden" data-menu-item="i5insights-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-ff3c606f-1300-4166-b132-0afe018376e0" href="/younata/Nimble/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph"> <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Insights </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu></div> </nav> </div> <turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class=""> <div id="repo-content-pjax-container" class="repository-content " > <h1 class='sr-only'>younata/Nimble</h1> <div class="clearfix container-xl px-md-4 px-lg-5 px-3"> <div> <div style="max-width: 100%" data-view-component="true" class="Layout Layout--flowRow-until-md react-repos-overview-margin Layout--sidebarPosition-end Layout--sidebarPosition-flowRow-end"> <div data-view-component="true" class="Layout-main"> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_dompurify_dist_purify_es_mjs-dd1d3ea6a436.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_tanstack_query-core_build_modern_queryObserver_js-node_modules_tanstack_-defd52-843b41414e0e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_aria-live_aria-live_ts-ui_packages_history_history_ts-ui_packages_promise-with-re-01dc80-b13b6c1d97b0.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_paths_index_ts-04e7ec2d63d9.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ref-selector_RefSelector_tsx-7496afc3784d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_commit-attribution_index_ts-ui_packages_commit-checks-status_index_ts-ui_packages-762eaa-d78307eadb45.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_code-view-shared_hooks_use-canonical-object_ts-ui_packages_code-view-shared_hooks-c2dbff-27f8152d69dc.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/repos-overview-5da4c053db4d.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.a490b7c9fa319e5cb069.module.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repos-overview.0ee7cac3ab511a65d9f9.module.css" /> <react-partial partial-name="repos-overview" data-ssr="true" data-attempted-ssr="true" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"initialPayload":{"allShortcutsEnabled":false,"path":"/","repo":{"id":338929302,"defaultBranch":"main","name":"Nimble","ownerLogin":"younata","currentUserCanPush":false,"isFork":true,"isEmpty":false,"createdAt":"2021-02-15T00:08:21.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/285321?v=4","public":true,"private":false,"isOrgOwned":false},"currentUser":null,"refInfo":{"name":"main","listCacheKey":"v0:1704872780.0","canEdit":false,"refType":"branch","currentOid":"32bb1fc65a1ecd52c295f5971b16034649217754"},"tree":{"items":[{"name":".github","path":".github","contentType":"directory"},{"name":"Nimble.xcodeproj","path":"Nimble.xcodeproj","contentType":"directory"},{"name":"Sources","path":"Sources","contentType":"directory"},{"name":"Tests","path":"Tests","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"script","path":"script","contentType":"directory"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".swiftlint.yml","path":".swiftlint.yml","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"Cartfile.resolved","path":"Cartfile.resolved","contentType":"file"},{"name":"Dockerfile.test","path":"Dockerfile.test","contentType":"file"},{"name":"Gemfile","path":"Gemfile","contentType":"file"},{"name":"Gemfile.lock","path":"Gemfile.lock","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"Nimble.podspec","path":"Nimble.podspec","contentType":"file"},{"name":"Package.resolved","path":"Package.resolved","contentType":"file"},{"name":"Package.swift","path":"Package.swift","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"test","path":"test","contentType":"file"}],"templateDirectorySuggestionUrl":null,"readme":null,"totalCount":19,"showBranchInfobar":true},"fileTree":null,"fileTreeProcessingTime":null,"foldersToFetch":[],"treeExpanded":false,"symbolsExpanded":false,"isOverview":true,"overview":{"banners":{"shouldRecommendReadme":false,"isPersonalRepo":false,"showUseActionBanner":false,"actionSlug":null,"actionId":null,"showProtectBranchBanner":false,"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_repo","releasePath":"/younata/Nimble/releases/new?marketplace=true","showPublishActionBanner":false},"interactionLimitBanner":null,"showInvitationBanner":false,"inviterName":null,"actionsMigrationBannerInfo":{"releaseTags":[],"showImmutableActionsMigrationBanner":false,"initialMigrationStatus":null}},"codeButton":{"contactPath":"/contact","isEnterprise":false,"local":{"protocolInfo":{"httpAvailable":true,"sshAvailable":null,"httpUrl":"https://github.com/younata/Nimble.git","showCloneWarning":null,"sshUrl":null,"sshCertificatesRequired":null,"sshCertificatesAvailable":null,"ghCliUrl":"gh repo clone younata/Nimble","defaultProtocol":"http","newSshKeyUrl":"/settings/ssh/new","setProtocolPath":"/users/set_protocol"},"platformInfo":{"cloneUrl":"https://desktop.github.com","showVisualStudioCloneButton":false,"visualStudioCloneUrl":"https://windows.github.com","showXcodeCloneButton":false,"xcodeCloneUrl":"xcode://clone?repo=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble","zipballUrl":"/younata/Nimble/archive/refs/heads/main.zip"}},"newCodespacePath":"/codespaces/new?hide_repo_select=true\u0026repo=338929302"},"popovers":{"rename":null,"renamedParentRepo":null},"commitCount":"1,914","overviewFiles":[{"displayName":"README.md","repoName":"Nimble","refName":"main","path":"README.md","preferredFileType":"readme","tabName":"README","richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNimble\u003c/h1\u003e\u003ca id=\"user-content-nimble\" class=\"anchor\" aria-label=\"Permalink: Nimble\" href=\"#nimble\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/Quick/Nimble/actions/workflows/ci-xcode.yml\"\u003e\u003cimg src=\"https://github.com/Quick/Nimble/actions/workflows/ci-xcode.yml/badge.svg\" alt=\"Build Status\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://cocoapods.org/pods/Nimble\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/017de8a282248d27c83840aac0d4dde210b0be9e04561d35101c2f6798c8ba7d/68747470733a2f2f696d672e736869656c64732e696f2f636f636f61706f64732f762f4e696d626c652e737667\" alt=\"CocoaPods\" data-canonical-src=\"https://img.shields.io/cocoapods/v/Nimble.svg\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5cb89494518efc818a124fd801726287be9482423d1a161a6dec2066aa0f30db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f43617274686167652d636f6d70617469626c652d3442433531442e7376673f7374796c653d666c6174\" alt=\"Carthage Compatible\" data-canonical-src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003ca href=\"https://cocoapods.org/pods/Nimble\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/915a4c2f0baf0e08e00091ebbb1b1f5c625a07d5e9a8715868d3d8ecd05e3f4f/68747470733a2f2f696d672e736869656c64732e696f2f636f636f61706f64732f702f4e696d626c652e737667\" alt=\"Platforms\" data-canonical-src=\"https://img.shields.io/cocoapods/p/Nimble.svg\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eUse Nimble to express the expected outcomes of Swift\nor Objective-C expressions. Inspired by\n\u003ca href=\"https://github.com/pivotal/cedar\"\u003eCedar\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nexpect(1 + 1).to(equal(2))\nexpect(1.2).to(beCloseTo(1.1, within: 0.1))\nexpect(3) \u0026gt; 2\nexpect(\u0026quot;seahorse\u0026quot;).to(contain(\u0026quot;sea\u0026quot;))\nexpect([\u0026quot;Atlantic\u0026quot;, \u0026quot;Pacific\u0026quot;]).toNot(contain(\u0026quot;Mississippi\u0026quot;))\nexpect(ocean.isClean).toEventually(beTruthy())\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1.2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeCloseTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e within\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eseahorse\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003esea\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eAtlantic\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ePacific\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMississippi\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eisClean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeTruthy\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eHow to Use Nimble\u003c/h1\u003e\u003ca id=\"user-content-how-to-use-nimble\" class=\"anchor\" aria-label=\"Permalink: How to Use Nimble\" href=\"#how-to-use-nimble\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\n\n\u003cp dir=\"auto\"\u003e\u003cstrong\u003eTable of Contents\u003c/strong\u003e \u003cem\u003egenerated with \u003ca href=\"https://github.com/thlorenz/doctoc\"\u003eDocToc\u003c/a\u003e\u003c/em\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#some-background-expressing-outcomes-using-assertions-in-xctest\"\u003eSome Background: Expressing Outcomes Using Assertions in XCTest\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#nimble-expectations-using-expectto\"\u003eNimble: Expectations Using \u003ccode\u003eexpect(...).to\u003c/code\u003e\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#custom-failure-messages\"\u003eCustom Failure Messages\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#type-safety\"\u003eType Safety\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#operator-overloads\"\u003eOperator Overloads\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#lazily-computed-values\"\u003eLazily Computed Values\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#c-primitives\"\u003eC Primitives\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#asyncawait-support\"\u003eAsync/Await Support\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#async-matchers\"\u003eAsync Matchers\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#polling-expectations\"\u003ePolling Expectations\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#using-polling-expectations-in-async-tests\"\u003eUsing Polling Expectations in Async Tests\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#verifying-a-matcher-will-never-or-always-match\"\u003eVerifying a Matcher will Never or Always Match\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#waiting-for-a-callback-to-be-called\"\u003eWaiting for a Callback to be Called\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#changing-the-timeout-and-polling-intervals\"\u003eChanging the Timeout and Polling Intervals\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#changing-default-timeout-and-poll-intervals\"\u003eChanging default Timeout and Poll Intervals\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#quick\"\u003eQuick\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#xctest\"\u003eXCTest\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#objective-c-support\"\u003eObjective-C Support\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#disabling-objective-c-shorthand\"\u003eDisabling Objective-C Shorthand\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-require-to-demand-that-a-matcher-pass-before-continuing\"\u003eUsing \u003ccode\u003erequire\u003c/code\u003e to demand that a matcher pass before continuing\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#polling-with-require\"\u003ePolling with \u003ccode\u003erequire\u003c/code\u003e.\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-require-with-async-expressions-and-async-matchers\"\u003eUsing \u003ccode\u003erequire\u003c/code\u003e with Async expressions and Async matchers\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-unwrap-to-replace-requiretonotbenil\"\u003eUsing \u003ccode\u003eunwrap\u003c/code\u003e to replace \u003ccode\u003erequire(...).toNot(beNil())\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#throwing-a-custom-error-from-require\"\u003eThrowing a Custom Error from Require\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#built-in-matcher-functions\"\u003eBuilt-in Matcher Functions\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#type-checking\"\u003eType Checking\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#equivalence\"\u003eEquivalence\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#identity\"\u003eIdentity\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#comparisons\"\u003eComparisons\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#typesclasses\"\u003eTypes/Classes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#truthiness\"\u003eTruthiness\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#swift-assertions\"\u003eSwift Assertions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#swift-error-handling\"\u003eSwift Error Handling\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#exceptions\"\u003eExceptions\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#collection-membership\"\u003eCollection Membership\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#strings\"\u003eStrings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#collection-elements\"\u003eCollection Elements\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#swift\"\u003eSwift\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#objective-c\"\u003eObjective-C\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#collection-count\"\u003eCollection Count\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#notifications\"\u003eNotifications\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#result\"\u003eResult\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#matching-a-value-to-any-of-a-group-of-matchers\"\u003eMatching a value to any of a group of matchers\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#custom-validation\"\u003eCustom Validation\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#writing-your-own-matchers\"\u003eWriting Your Own Matchers\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#matcherresult\"\u003eMatcherResult\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#lazy-evaluation\"\u003eLazy Evaluation\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#type-checking-via-swift-generics\"\u003eType Checking via Swift Generics\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#customizing-failure-messages\"\u003eCustomizing Failure Messages\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#basic-customization\"\u003eBasic Customization\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#full-customization\"\u003eFull Customization\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#asynchronous-matchers\"\u003eAsynchronous Matchers\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#supporting-objective-c\"\u003eSupporting Objective-C\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#properly-handling-nil-in-objective-c-matchers\"\u003eProperly Handling \u003ccode\u003enil\u003c/code\u003e in Objective-C Matchers\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#installing-nimble\"\u003eInstalling Nimble\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#installing-nimble-as-a-submodule\"\u003eInstalling Nimble as a Submodule\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#installing-nimble-via-cocoapods\"\u003eInstalling Nimble via CocoaPods\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#installing-nimble-via-swift-package-manager\"\u003eInstalling Nimble via Swift Package Manager\u003c/a\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ca href=\"#xcode\"\u003eXcode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#packageswift\"\u003ePackage.Swift\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-nimble-without-xctest\"\u003eUsing Nimble without XCTest\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSome Background: Expressing Outcomes Using Assertions in XCTest\u003c/h1\u003e\u003ca id=\"user-content-some-background-expressing-outcomes-using-assertions-in-xctest\" class=\"anchor\" aria-label=\"Permalink: Some Background: Expressing Outcomes Using Assertions in XCTest\" href=\"#some-background-expressing-outcomes-using-assertions-in-xctest\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eApple's Xcode includes the XCTest framework, which provides\nassertion macros to test whether code behaves properly.\nFor example, to assert that \u003ccode\u003e1 + 1 = 2\u003c/code\u003e, XCTest has you write:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nXCTAssertEqual(1 + 1, 2, \u0026quot;expected one plus one to equal two\u0026quot;)\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eXCTAssertEqual\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eexpected one plus one to equal two\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOr, in Objective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nXCTAssertEqual(1 + 1, 2, @\u0026quot;expected one plus one to equal two\u0026quot;);\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eXCTAssertEqual\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e + \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eexpected one plus one to equal two\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e);\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eXCTest assertions have a couple of drawbacks:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eNot enough macros.\u003c/strong\u003e There's no easy way to assert that a string\ncontains a particular substring, or that a number is less than or\nequal to another.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIt's hard to write asynchronous tests.\u003c/strong\u003e XCTest forces you to write\na lot of boilerplate code.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eNimble addresses these concerns.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNimble: Expectations Using \u003ccode\u003eexpect(...).to\u003c/code\u003e\u003c/h1\u003e\u003ca id=\"user-content-nimble-expectations-using-expectto\" class=\"anchor\" aria-label=\"Permalink: Nimble: Expectations Using expect(...).to\" href=\"#nimble-expectations-using-expectto\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble allows you to express expectations using a natural,\neasily understood language:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nimport Nimble\n\nexpect(seagull.squawk).to(equal(\u0026quot;Squee!\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e Nimble\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eseagull\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esquawk\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eSquee!\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n@import Nimble;\n\nexpect(seagull.squawk).to(equal(@\u0026quot;Squee!\u0026quot;));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n@import Nimble;\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(seagull.squawk).to(equal(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eSquee!\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003eexpect\u003c/code\u003e function autocompletes to include \u003ccode\u003efile:\u003c/code\u003e and \u003ccode\u003eline:\u003c/code\u003e,\nbut these parameters are optional. Use the default values to have\nXcode highlight the correct line when an expectation is not met.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eTo perform the opposite expectation--to assert something is \u003cem\u003enot\u003c/em\u003e\nequal--use \u003ccode\u003etoNot\u003c/code\u003e or \u003ccode\u003enotTo\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nimport Nimble\n\nexpect(seagull.squawk).toNot(equal(\u0026quot;Oh, hello there!\u0026quot;))\nexpect(seagull.squawk).notTo(equal(\u0026quot;Oh, hello there!\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e Nimble\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eseagull\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esquawk\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eOh, hello there!\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eseagull\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esquawk\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003enotTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eOh, hello there!\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n@import Nimble;\n\nexpect(seagull.squawk).toNot(equal(@\u0026quot;Oh, hello there!\u0026quot;));\nexpect(seagull.squawk).notTo(equal(@\u0026quot;Oh, hello there!\u0026quot;));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n@import Nimble;\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(seagull.squawk).toNot(equal(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eOh, hello there!\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(seagull.squawk).notTo(equal(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eOh, hello there!\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustom Failure Messages\u003c/h2\u003e\u003ca id=\"user-content-custom-failure-messages\" class=\"anchor\" aria-label=\"Permalink: Custom Failure Messages\" href=\"#custom-failure-messages\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWould you like to add more information to the test's failure messages? Use the \u003ccode\u003edescription\u003c/code\u003e optional argument to add your own text:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(1 + 1).to(equal(3))\n// failed - expected to equal \u0026lt;3\u0026gt;, got \u0026lt;2\u0026gt;\n\nexpect(1 + 1).to(equal(3), description: \u0026quot;Make sure libKindergartenMath is loaded\u0026quot;)\n// failed - Make sure libKindergartenMath is loaded\n// expected to equal \u0026lt;3\u0026gt;, got \u0026lt;2\u0026gt;\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n// failed - expected to equal \u0026lt;3\u0026gt;, got \u0026lt;2\u0026gt;\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e description\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMake sure libKindergartenMath is loaded\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n// failed - Make sure libKindergartenMath is loaded\n// expected to equal \u0026lt;3\u0026gt;, got \u0026lt;2\u0026gt;\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOr the *WithDescription version in Objective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n@import Nimble;\n\nexpect(@(1+1)).to(equal(@3));\n// failed - expected to equal \u0026lt;3.0000\u0026gt;, got \u0026lt;2.0000\u0026gt;\n\nexpect(@(1+1)).toWithDescription(equal(@3), @\u0026quot;Make sure libKindergartenMath is loaded\u0026quot;);\n// failed - Make sure libKindergartenMath is loaded\n// expected to equal \u0026lt;3.0000\u0026gt;, got \u0026lt;2.0000\u0026gt;\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n@import Nimble;\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e+\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e)).to(equal(@\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e));\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e failed - expected to equal \u0026lt;3.0000\u0026gt;, got \u0026lt;2.0000\u0026gt;\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e+\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e)).toWithDescription(equal(@\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e), @\"Make sure libKindergartenMath is loaded\");\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e failed - Make sure libKindergartenMath is loaded\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e expected to equal \u0026lt;3.0000\u0026gt;, got \u0026lt;2.0000\u0026gt;\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eType Safety\u003c/h2\u003e\u003ca id=\"user-content-type-safety\" class=\"anchor\" aria-label=\"Permalink: Type Safety\" href=\"#type-safety\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble makes sure you don't compare two types that don't match:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Does not compile:\nexpect(1 + 1).to(equal(\u0026quot;Squee!\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\n// Does not compile:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e+\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eSquee!\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eNimble uses generics--only available in Swift--to ensure\ntype correctness. That means type checking is\nnot available when using Nimble in Objective-C. 😭\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOperator Overloads\u003c/h2\u003e\u003ca id=\"user-content-operator-overloads\" class=\"anchor\" aria-label=\"Permalink: Operator Overloads\" href=\"#operator-overloads\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTired of so much typing? With Nimble, you can use overloaded operators\nlike \u003ccode\u003e==\u003c/code\u003e for equivalence, or \u003ccode\u003e\u0026gt;\u003c/code\u003e for comparisons:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if squawk does not equal \u0026quot;Hi!\u0026quot;:\nexpect(seagull.squawk) != \u0026quot;Hi!\u0026quot;\n\n// Passes if 10 is greater than 2:\nexpect(10) \u0026gt; 2\"\u003e\u003cpre\u003e// Swift\n\n// Passes if squawk does not equal \"Hi!\":\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eseagull\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esquawk\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eHi!\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\n\n// Passes if 10 is greater than 2:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eOperator overloads are only available in Swift, so you won't be able\nto use this syntax in Objective-C. 💔\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLazily Computed Values\u003c/h2\u003e\u003ca id=\"user-content-lazily-computed-values\" class=\"anchor\" aria-label=\"Permalink: Lazily Computed Values\" href=\"#lazily-computed-values\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003eexpect\u003c/code\u003e function doesn't evaluate the value it's given until it's\ntime to match. So Nimble can test whether an expression raises an\nexception once evaluated:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Note: Swift currently doesn't have exceptions.\n// Only Objective-C code can raise exceptions\n// that Nimble will catch.\n// (see https://github.com/Quick/Nimble/issues/220#issuecomment-172667064)\nlet exception = NSException(\n name: NSInternalInconsistencyException,\n reason: \u0026quot;Not enough fish in the sea.\u0026quot;,\n userInfo: [\u0026quot;something\u0026quot;: \u0026quot;is fishy\u0026quot;])\nexpect { exception.raise() }.to(raiseException())\n\n// Also, you can customize raiseException to be more specific\nexpect { exception.raise() }.to(raiseException(named: NSInternalInconsistencyException))\nexpect { exception.raise() }.to(raiseException(\n named: NSInternalInconsistencyException,\n reason: \u0026quot;Not enough fish in the sea\u0026quot;))\nexpect { exception.raise() }.to(raiseException(\n named: NSInternalInconsistencyException,\n reason: \u0026quot;Not enough fish in the sea\u0026quot;,\n userInfo: [\u0026quot;something\u0026quot;: \u0026quot;is fishy\u0026quot;]))\"\u003e\u003cpre\u003e// Swift\n\n// Note: Swift currently doesn't have exceptions.\n// Only Objective-C code can raise exceptions\n// that Nimble will catch.\n// (see https://github.com/Quick/Nimble/issues/220#issuecomment-172667064)\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNSException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n name\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e NSInternalInconsistencyException\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n reason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eNot enough fish in the sea.\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n userInfo\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003esomething\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eis fishy\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e exception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraise\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Also, you can customize raiseException to be more specific\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e exception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraise\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003enamed\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e NSInternalInconsistencyException\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e exception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraise\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n named\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e NSInternalInconsistencyException\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n reason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eNot enough fish in the sea\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e exception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraise\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n named\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e NSInternalInconsistencyException\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n reason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eNot enough fish in the sea\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n userInfo\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003esomething\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eis fishy\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eObjective-C works the same way, but you must use the \u003ccode\u003eexpectAction\u003c/code\u003e\nmacro when making an expectation on an expression that has no return\nvalue:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nNSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException\n reason:@\u0026quot;Not enough fish in the sea.\u0026quot;\n userInfo:nil];\nexpectAction(^{ [exception raise]; }).to(raiseException());\n\n// Use the property-block syntax to be more specific.\nexpectAction(^{ [exception raise]; }).to(raiseException().named(NSInternalInconsistencyException));\nexpectAction(^{ [exception raise]; }).to(raiseException().\n named(NSInternalInconsistencyException).\n reason(\u0026quot;Not enough fish in the sea\u0026quot;));\nexpectAction(^{ [exception raise]; }).to(raiseException().\n named(NSInternalInconsistencyException).\n reason(\u0026quot;Not enough fish in the sea\u0026quot;).\n userInfo(@{@\u0026quot;something\u0026quot;: @\u0026quot;is fishy\u0026quot;}));\n\n// You can also pass a block for custom matching of the raised exception\nexpectAction(exception.raise()).to(raiseException().satisfyingBlock(^(NSException *exception) {\n expect(exception.name).to(beginWith(NSInternalInconsistencyException));\n}));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eNSException\u003c/span\u003e *\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e = [\u003cspan class=\"pl-c1\"\u003eNSException\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eexceptionWithName:\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eNSInternalInconsistencyException\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003ereason:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eNot enough fish in the sea.\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003euserInfo:\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003enil\u003c/span\u003e];\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(^{ [\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eraise\u003c/span\u003e]; }).to(raiseException());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Use the property-block syntax to be more specific.\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(^{ [\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eraise\u003c/span\u003e]; }).to(raiseException().named(\u003cspan class=\"pl-c1\"\u003eNSInternalInconsistencyException\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(^{ [\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eraise\u003c/span\u003e]; }).to(raiseException().\n named(\u003cspan class=\"pl-c1\"\u003eNSInternalInconsistencyException\u003c/span\u003e).\n reason(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eNot enough fish in the sea\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(^{ [\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eraise\u003c/span\u003e]; }).to(raiseException().\n named(\u003cspan class=\"pl-c1\"\u003eNSInternalInconsistencyException\u003c/span\u003e).\n reason(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eNot enough fish in the sea\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e).\n userInfo(@{\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003esomething\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eis fishy\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e}));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e You can also pass a block for custom matching of the raised exception\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e.raise()).to(raiseException().satisfyingBlock(^(\u003cspan class=\"pl-c1\"\u003eNSException\u003c/span\u003e *\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e) {\n \u003cspan class=\"pl-c1\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e.\u003cspan class=\"pl-smi\"\u003ename\u003c/span\u003e).\u003cspan class=\"pl-c1\"\u003eto\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003ebeginWith\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eNSInternalInconsistencyException\u003c/span\u003e));\n}));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eC Primitives\u003c/h2\u003e\u003ca id=\"user-content-c-primitives\" class=\"anchor\" aria-label=\"Permalink: C Primitives\" href=\"#c-primitives\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSome testing frameworks make it hard to test primitive C values.\nIn Nimble, it just works:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nlet actual: CInt = 1\nlet expectedValue: CInt = 1\nexpect(actual).to(equal(expectedValue))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactual\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eCInt\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eexpectedValue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eCInt\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpectedValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn fact, Nimble uses type inference, so you can write the above\nwithout explicitly specifying both types:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(1 as CInt).to(equal(1))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eCInt\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eIn Objective-C, Nimble only supports Objective-C objects. To\nmake expectations on primitive C values, wrap then in an object\nliteral:\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"expect(@(1 + 1)).to(equal(@2));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e + \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e)).to(equal(@\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAsync/Await Support\u003c/h2\u003e\u003ca id=\"user-content-asyncawait-support\" class=\"anchor\" aria-label=\"Permalink: Async/Await Support\" href=\"#asyncawait-support\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble makes it easy to await for an async function to complete. Simply pass\nthe async function in to \u003ccode\u003eexpect\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nawait expect { await aFunctionReturning1() }.to(equal(1))\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eaFunctionReturning1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe async function is awaited on first, before passing it to the matcher. This\nenables the matcher to run synchronous code like before, without caring about\nwhether the value it's processing was abtained async or not.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAsync support is Swift-only, and it requires that you execute the test in an\nasync context. For XCTest, this is as simple as marking your test function with\n\u003ccode\u003easync\u003c/code\u003e. If you use Quick, all tests in Quick 6 are executed in an async context.\nIn Quick 7 and later, only tests that are in an \u003ccode\u003eAsyncSpec\u003c/code\u003e subclass will be\nexecuted in an async context.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eTo avoid a compiler errors when using synchronous \u003ccode\u003eexpect\u003c/code\u003e in asynchronous contexts,\n\u003ccode\u003eexpect\u003c/code\u003e with async expressions does not support autoclosures. However, the \u003ccode\u003eexpecta\u003c/code\u003e\n(expect async) function is provided as an alternative, which does support autoclosures.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nawait expecta(await aFunctionReturning1()).to(equal(1)))\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eexpecta\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eaFunctionReturning1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSimilarly, if you're ever in a situation where you want to force the compiler to\nproduce a \u003ccode\u003eSyncExpectation\u003c/code\u003e, you can use the \u003ccode\u003eexpects\u003c/code\u003e (expect sync) function to\nproduce a \u003ccode\u003eSyncExpectation\u003c/code\u003e. Like so:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nexpects(someNonAsyncFunction()).to(equal(1)))\n\nexpects(await someAsyncFunction()).to(equal(1)) // Compiler error: 'async' call in an autoclosure that does not support concurrency\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-en\"\u003eexpects\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esomeNonAsyncFunction\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpects\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomeAsyncFunction\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e // Compiler error: 'async' call in an autoclosure that does not support concurrency\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAsync Matchers\u003c/h3\u003e\u003ca id=\"user-content-async-matchers\" class=\"anchor\" aria-label=\"Permalink: Async Matchers\" href=\"#async-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn addition to asserting on async functions prior to passing them to a\nsynchronous matcher, you can also write matchers that directly take in an\nasync value. These are called \u003ccode\u003eAsyncMatcher\u003c/code\u003es. This is most obviously useful\nwhen directly asserting against an actor. In addition to writing your own\nasync matchers, Nimble currently ships with async versions of the following\nmatchers:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eallPass\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003econtainElementSatisfying\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esatisfyAllOf\u003c/code\u003e and the \u003ccode\u003e\u0026amp;\u0026amp;\u003c/code\u003e operator overload accept both \u003ccode\u003eAsyncMatcher\u003c/code\u003e and\nsynchronous \u003ccode\u003eMatcher\u003c/code\u003es.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esatisfyAnyOf\u003c/code\u003e and the \u003ccode\u003e||\u003c/code\u003e operator overload accept both \u003ccode\u003eAsyncMatcher\u003c/code\u003e and\nsynchronous \u003ccode\u003eMatcher\u003c/code\u003es.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eNote: Async/Await support is different than the \u003ccode\u003etoEventually\u003c/code\u003e/\u003ccode\u003etoEventuallyNot\u003c/code\u003e\nfeature described below.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePolling Expectations\u003c/h2\u003e\u003ca id=\"user-content-polling-expectations\" class=\"anchor\" aria-label=\"Permalink: Polling Expectations\" href=\"#polling-expectations\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn Nimble, it's easy to make expectations on values that are updated\nasynchronously. Just use \u003ccode\u003etoEventually\u003c/code\u003e or \u003ccode\u003etoEventuallyNot\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nDispatchQueue.main.async {\n ocean.add(\u0026quot;dolphins\u0026quot;)\n ocean.add(\u0026quot;whales\u0026quot;)\n}\nexpect(ocean).toEventually(contain(\u0026quot;dolphins\u0026quot;, \u0026quot;whales\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-smi\"\u003eDispatchQueue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emain\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003cspan class=\"pl-k\"\u003easync\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphins\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewhales\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphins\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewhales\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\ndispatch_async(dispatch_get_main_queue(), ^{\n [ocean add:@\u0026quot;dolphins\u0026quot;];\n [ocean add:@\u0026quot;whales\u0026quot;];\n});\nexpect(ocean).toEventually(contain(@\u0026quot;dolphins\u0026quot;, @\u0026quot;whales\u0026quot;));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003edispatch_async\u003c/span\u003e(dispatch_get_main_queue(), ^{\n [ocean \u003cspan class=\"pl-c1\"\u003eadd:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphins\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\n [ocean \u003cspan class=\"pl-c1\"\u003eadd:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewhales\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\n});\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(ocean).toEventually(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphins\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewhales\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: toEventually triggers its polls on the main thread. Blocking the main\nthread will cause Nimble to stop the run loop. This can cause test pollution\nfor whatever incomplete code that was running on the main thread. Blocking the\nmain thread can be caused by blocking IO, calls to sleep(), deadlocks, and\nsynchronous IPC.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIn the above example, \u003ccode\u003eocean\u003c/code\u003e is constantly re-evaluated. If it ever\ncontains dolphins and whales, the expectation passes. If \u003ccode\u003eocean\u003c/code\u003e still\ndoesn't contain them, even after being continuously re-evaluated for one\nwhole second, the expectation fails.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsing Polling Expectations in Async Tests\u003c/h3\u003e\u003ca id=\"user-content-using-polling-expectations-in-async-tests\" class=\"anchor\" aria-label=\"Permalink: Using Polling Expectations in Async Tests\" href=\"#using-polling-expectations-in-async-tests\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can easily use \u003ccode\u003etoEventually\u003c/code\u003e or \u003ccode\u003etoEventuallyNot\u003c/code\u003e in async contexts as\nwell. You only need to add an \u003ccode\u003eawait\u003c/code\u003e statement to the beginning of the line:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nDispatchQueue.main.async {\n ocean.add(\u0026quot;dolphins\u0026quot;)\n ocean.add(\u0026quot;whales\u0026quot;)\n}\nawait expect(ocean).toEventually(contain(\u0026quot;dolphens\u0026quot;, \u0026quot;whiles\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-smi\"\u003eDispatchQueue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emain\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003cspan class=\"pl-k\"\u003easync\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphins\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewhales\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphens\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewhiles\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eStarting in Nimble 12, \u003ccode\u003etoEventually\u003c/code\u003e et. al. now also supports async\nexpectations. For example, the following test is now supported:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"actor MyActor {\n private var counter = 0\n\n func access() -\u0026gt; Int {\n counter += 1\n return counter\n }\n}\n\nlet subject = MyActor()\nawait expect { await subject.access() }.toEventually(equal(2))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eactor\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMyActor\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003ecounter\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e\n\n \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e access\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInt\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n counter \u003cspan class=\"pl-c1\"\u003e+=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e counter\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003esubject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMyActor\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e subject\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eaccess\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eVerifying a Matcher will Never or Always Match\u003c/h3\u003e\u003ca id=\"user-content-verifying-a-matcher-will-never-or-always-match\" class=\"anchor\" aria-label=\"Permalink: Verifying a Matcher will Never or Always Match\" href=\"#verifying-a-matcher-will-never-or-always-match\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can also test that a value always or never matches throughout the length of the timeout. Use \u003ccode\u003etoNever\u003c/code\u003e and \u003ccode\u003etoAlways\u003c/code\u003e for this:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nocean.add(\u0026quot;dolphins\u0026quot;)\nexpect(ocean).toAlways(contain(\u0026quot;dolphins\u0026quot;))\nexpect(ocean).toNever(contain(\u0026quot;hares\u0026quot;))\"\u003e\u003cpre\u003e// Swift\nocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphins\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoAlways\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphins\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNever\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ehares\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n[ocean add:@\u0026quot;dolphins\u0026quot;]\nexpect(ocean).toAlways(contain(@\u0026quot;dolphins\u0026quot;))\nexpect(ocean).toNever(contain(@\u0026quot;hares\u0026quot;))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n[ocean \u003cspan class=\"pl-c1\"\u003eadd:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphins\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e]\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(ocean).toAlways(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphins\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e))\nexpect(ocean).toNever(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ehares\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e))\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWaiting for a Callback to be Called\u003c/h3\u003e\u003ca id=\"user-content-waiting-for-a-callback-to-be-called\" class=\"anchor\" aria-label=\"Permalink: Waiting for a Callback to be Called\" href=\"#waiting-for-a-callback-to-be-called\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can also provide a callback by using the \u003ccode\u003ewaitUntil\u003c/code\u003e function:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nwaitUntil { done in\n ocean.goFish { success in\n expect(success).to(beTrue())\n done()\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003ewaitUntil\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e done \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003egoFish\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e success \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003esuccess\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeTrue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003edone\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nwaitUntil(^(void (^done)(void)){\n [ocean goFishWithHandler:^(BOOL success){\n expect(success).to(beTrue());\n done();\n }];\n});\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003ewaitUntil\u003c/span\u003e(^(\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e (^done)(\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e)){\n [ocean \u003cspan class=\"pl-c1\"\u003egoFishWithHandler:\u003c/span\u003e^(\u003cspan class=\"pl-c1\"\u003eBOOL\u003c/span\u003e success){\n \u003cspan class=\"pl-c1\"\u003eexpect\u003c/span\u003e(success).\u003cspan class=\"pl-c1\"\u003eto\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003ebeTrue\u003c/span\u003e());\n \u003cspan class=\"pl-c1\"\u003edone\u003c/span\u003e();\n }];\n});\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ewaitUntil\u003c/code\u003e also optionally takes a timeout parameter:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nwaitUntil(timeout: .seconds(10)) { done in\n ocean.goFish { success in\n expect(success).to(beTrue())\n done()\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003ewaitUntil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003etimeout\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e done \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n ocean\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003egoFish\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e success \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003esuccess\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeTrue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003edone\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nwaitUntilTimeout(10, ^(void (^done)(void)){\n [ocean goFishWithHandler:^(BOOL success){\n expect(success).to(beTrue());\n done();\n }];\n});\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003ewaitUntilTimeout\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e, ^(\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e (^done)(\u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e)){\n [ocean \u003cspan class=\"pl-c1\"\u003egoFishWithHandler:\u003c/span\u003e^(\u003cspan class=\"pl-c1\"\u003eBOOL\u003c/span\u003e success){\n \u003cspan class=\"pl-c1\"\u003eexpect\u003c/span\u003e(success).\u003cspan class=\"pl-c1\"\u003eto\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003ebeTrue\u003c/span\u003e());\n \u003cspan class=\"pl-c1\"\u003edone\u003c/span\u003e();\n }];\n});\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: \u003ccode\u003ewaitUntil\u003c/code\u003e triggers its timeout code on the main thread. Blocking the main\nthread will cause Nimble to stop the run loop to continue. This can cause test\npollution for whatever incomplete code that was running on the main thread.\nBlocking the main thread can be caused by blocking IO, calls to sleep(),\ndeadlocks, and synchronous IPC.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eChanging the Timeout and Polling Intervals\u003c/h3\u003e\u003ca id=\"user-content-changing-the-timeout-and-polling-intervals\" class=\"anchor\" aria-label=\"Permalink: Changing the Timeout and Polling Intervals\" href=\"#changing-the-timeout-and-polling-intervals\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSometimes it takes more than a second for a value to update. In those\ncases, use the \u003ccode\u003etimeout\u003c/code\u003e parameter:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Waits three seconds for ocean to contain \u0026quot;starfish\u0026quot;:\nexpect(ocean).toEventually(contain(\u0026quot;starfish\u0026quot;), timeout: .seconds(3))\n\n// Evaluate someValue every 0.2 seconds repeatedly until it equals 100, or fails if it timeouts after 5.5 seconds.\nexpect(someValue).toEventually(equal(100), timeout: .milliseconds(5500), pollInterval: .milliseconds(200))\"\u003e\u003cpre\u003e// Swift\n\n// Waits three seconds for ocean to contain \"starfish\":\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eocean\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003estarfish\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e timeout\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Evaluate someValue every 0.2 seconds repeatedly until it equals 100, or fails if it timeouts after 5.5 seconds.\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003esomeValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e timeout\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emilliseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5500\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e pollInterval\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emilliseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e200\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Waits three seconds for ocean to contain \u0026quot;starfish\u0026quot;:\nexpect(ocean).withTimeout(3).toEventually(contain(@\u0026quot;starfish\u0026quot;));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Waits three seconds for ocean to contain \"starfish\":\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(ocean).withTimeout(\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e).toEventually(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003estarfish\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eChanging default Timeout and Poll Intervals\u003c/h3\u003e\u003ca id=\"user-content-changing-default-timeout-and-poll-intervals\" class=\"anchor\" aria-label=\"Permalink: Changing default Timeout and Poll Intervals\" href=\"#changing-default-timeout-and-poll-intervals\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn some cases (e.g. when running on slower machines) it can be useful to modify\nthe default timeout and poll interval values. This can be done as follows:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Increase the global timeout to 5 seconds:\nNimble.PollingDefaults.timeout = .seconds(5)\n\n// Slow the polling interval to 0.1 seconds:\nNimble.PollingDefaults.pollInterval = .milliseconds(100)\"\u003e\u003cpre\u003e// Swift\n\n// Increase the global timeout to 5 seconds:\n\u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etimeout \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Slow the polling interval to 0.1 seconds:\n\u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003epollInterval \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emilliseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can set these globally at test startup in two ways:\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eQuick\u003c/h4\u003e\u003ca id=\"user-content-quick\" class=\"anchor\" aria-label=\"Permalink: Quick\" href=\"#quick\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf you use \u003ca href=\"https://github.com/Quick/Quick\"\u003eQuick\u003c/a\u003e, add a \u003ca href=\"https://github.com/Quick/Quick/blob/main/Documentation/en-us/ConfiguringQuick.md\"\u003e\u003ccode\u003eQuickConfiguration\u003c/code\u003e subclass\u003c/a\u003e which sets your desired \u003ccode\u003ePollingDefaults\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"import Quick\nimport Nimble\n\nclass PollingConfiguration: QuickConfiguration {\n override class func configure(_ configuration: QCKConfiguration) {\n Nimble.PollingDefaults.timeout = .seconds(5)\n Nimble.PollingDefaults.pollInterval = .milliseconds(100)\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e Quick\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e Nimble\n\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003ePollingConfiguration\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eQuickConfiguration\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003e\u003cspan class=\"pl-k\"\u003eoverride\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e configure\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e_ configuration\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eQCKConfiguration\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etimeout \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003epollInterval \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emilliseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch4 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eXCTest\u003c/h4\u003e\u003ca id=\"user-content-xctest\" class=\"anchor\" aria-label=\"Permalink: XCTest\" href=\"#xctest\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf you use \u003ca href=\"https://developer.apple.com/documentation/xctest\" rel=\"nofollow\"\u003eXCTest\u003c/a\u003e, add an object that conforms to \u003ca href=\"https://developer.apple.com/documentation/xctest/xctestobservation\" rel=\"nofollow\"\u003e\u003ccode\u003eXCTestObservation\u003c/code\u003e\u003c/a\u003e and implement \u003ca href=\"https://developer.apple.com/documentation/xctest/xctestobservation/1500772-testbundlewillstart\" rel=\"nofollow\"\u003e\u003ccode\u003etestBundleWillStart(_:)\u003c/code\u003e\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAdditionally, you will need to register this observer with the \u003ca href=\"https://developer.apple.com/documentation/xctest/xctestobservationcenter\" rel=\"nofollow\"\u003e\u003ccode\u003eXCTestObservationCenter\u003c/code\u003e\u003c/a\u003e at test startup. To do this, set the \u003ccode\u003eNSPrincipalClass\u003c/code\u003e key in your test bundle's Info.plist and implement a class with that same name.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-text-xml notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"\u0026lt;!-- Info.plist --\u0026gt;\n\u0026lt;?xml version=\u0026quot;1.0\u0026quot; encoding=\u0026quot;UTF-8\u0026quot;?\u0026gt;\n\u0026lt;!DOCTYPE plist PUBLIC \u0026quot;-//Apple//DTD PLIST 1.0//EN\u0026quot; \u0026quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd\u0026quot;\u0026gt;\n\u0026lt;plist version=\u0026quot;1.0\u0026quot;\u0026gt;\n\u0026lt;dict\u0026gt;\n \u0026lt;!-- ... --\u0026gt;\n\t\u0026lt;key\u0026gt;NSPrincipalClass\u0026lt;/key\u0026gt;\n\t\u0026lt;string\u0026gt;MyTests.TestSetup\u0026lt;/string\u0026gt;\n\u0026lt;/dict\u0026gt;\n\u0026lt;/plist\u0026gt;\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e\u0026lt;!--\u003c/span\u003e Info.plist \u003cspan class=\"pl-c\"\u003e--\u0026gt;\u003c/span\u003e\u003c/span\u003e\n\u0026lt;?\u003cspan class=\"pl-ent\"\u003exml\u003c/span\u003e\u003cspan class=\"pl-e\"\u003e version\u003c/span\u003e=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e1.0\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-e\"\u003e encoding\u003c/span\u003e=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eUTF-8\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e?\u0026gt;\n\u0026lt;!\u003cspan class=\"pl-ent\"\u003eDOCTYPE\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eplist\u003c/span\u003e PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u0026gt;\n\u0026lt;\u003cspan class=\"pl-ent\"\u003eplist\u003c/span\u003e \u003cspan class=\"pl-e\"\u003eversion\u003c/span\u003e=\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e1.0\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\u0026gt;\n\u0026lt;\u003cspan class=\"pl-ent\"\u003edict\u003c/span\u003e\u0026gt;\n \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e\u0026lt;!--\u003c/span\u003e ... \u003cspan class=\"pl-c\"\u003e--\u0026gt;\u003c/span\u003e\u003c/span\u003e\n\t\u0026lt;\u003cspan class=\"pl-ent\"\u003ekey\u003c/span\u003e\u0026gt;NSPrincipalClass\u0026lt;/\u003cspan class=\"pl-ent\"\u003ekey\u003c/span\u003e\u0026gt;\n\t\u0026lt;\u003cspan class=\"pl-ent\"\u003estring\u003c/span\u003e\u0026gt;MyTests.TestSetup\u0026lt;/\u003cspan class=\"pl-ent\"\u003estring\u003c/span\u003e\u0026gt;\n\u0026lt;/\u003cspan class=\"pl-ent\"\u003edict\u003c/span\u003e\u0026gt;\n\u0026lt;/\u003cspan class=\"pl-ent\"\u003eplist\u003c/span\u003e\u0026gt;\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// TestSetup.swift\nimport XCTest\nimport Nimble\n\n@objc\nclass TestSetup: NSObject {\n\toverride init() {\n\t\tXCTestObservationCenter.shared.register(PollingConfigurationTestObserver())\n\t}\n}\n\nclass PollingConfigurationTestObserver: NSObject, XCTestObserver {\n func testBundleWillStart(_ testBundle: Bundle) {\n Nimble.PollingDefaults.timeout = .seconds(5)\n Nimble.PollingDefaults.pollInterval = .milliseconds(100)\n }\n}\"\u003e\u003cpre\u003e// TestSetup.swift\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e XCTest\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e Nimble\n\n\u003cspan class=\"pl-s1\"\u003e@\u003cspan class=\"pl-smi\"\u003eobjc\u003c/span\u003e\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eTestSetup\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNSObject\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n\t\u003cspan class=\"pl-k\"\u003e\u003cspan class=\"pl-k\"\u003eoverride\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-v\"\u003einit\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n\t\t\u003cspan class=\"pl-smi\"\u003eXCTestObservationCenter\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eshared\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eregister\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ePollingConfigurationTestObserver\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\t\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003ePollingConfigurationTestObserver\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNSObject\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eXCTestObserver\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e testBundleWillStart\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e_ testBundle\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eBundle\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etimeout \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePollingDefaults\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003epollInterval \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003emilliseconds\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e100\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn Linux, you can implement \u003ccode\u003eLinuxMain\u003c/code\u003e to set the PollingDefaults before calling \u003ccode\u003eXCTMain\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eObjective-C Support\u003c/h2\u003e\u003ca id=\"user-content-objective-c-support\" class=\"anchor\" aria-label=\"Permalink: Objective-C Support\" href=\"#objective-c-support\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble has full support for Objective-C. However, there are two things\nto keep in mind when using Nimble in Objective-C:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eAll parameters passed to the \u003ccode\u003eexpect\u003c/code\u003e function, as well as matcher\nfunctions like \u003ccode\u003eequal\u003c/code\u003e, must be Objective-C objects or can be converted into\nan \u003ccode\u003eNSObject\u003c/code\u003e equivalent:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n@import Nimble;\n\nexpect(@(1 + 1)).to(equal(@2));\nexpect(@\u0026quot;Hello world\u0026quot;).to(contain(@\u0026quot;world\u0026quot;));\n\n// Boxed as NSNumber *\nexpect(2).to(equal(2));\nexpect(1.2).to(beLessThan(2.0));\nexpect(true).to(beTruthy());\n\n// Boxed as NSString *\nexpect(\u0026quot;Hello world\u0026quot;).to(equal(\u0026quot;Hello world\u0026quot;));\n\n// Boxed as NSRange\nexpect(NSMakeRange(1, 10)).to(equal(NSMakeRange(1, 10)));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n@import Nimble;\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e + \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e)).to(equal(@\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eHello world\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e).to(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eworld\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Boxed as NSNumber *\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e).to(equal(\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1.2\u003c/span\u003e).to(beLessThan(\u003cspan class=\"pl-c1\"\u003e2.0\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e).to(beTruthy());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Boxed as NSString *\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eHello world\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e).to(equal(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eHello world\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Boxed as NSRange\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eNSMakeRange\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e)).to(equal(\u003cspan class=\"pl-c1\"\u003eNSMakeRange\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e)));\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eTo make an expectation on an expression that does not return a value,\nsuch as \u003ccode\u003e-[NSException raise]\u003c/code\u003e, use \u003ccode\u003eexpectAction\u003c/code\u003e instead of\n\u003ccode\u003eexpect\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpectAction(^{ [exception raise]; }).to(raiseException());\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpectAction\u003c/span\u003e(^{ [\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eraise\u003c/span\u003e]; }).to(raiseException());\u003c/pre\u003e\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eThe following types are currently converted to an \u003ccode\u003eNSObject\u003c/code\u003e type:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003eC Numeric types\u003c/strong\u003e are converted to \u003ccode\u003eNSNumber *\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eNSRange\u003c/code\u003e is converted to \u003ccode\u003eNSValue *\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003echar *\u003c/code\u003e is converted to \u003ccode\u003eNSString *\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eFor the following matchers:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eequal\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeGreaterThan\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeGreaterThanOrEqual\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeLessThan\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeLessThanOrEqual\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeCloseTo\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeTrue\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeFalse\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeTruthy\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ebeFalsy\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehaveCount\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eIf you would like to see more, \u003ca href=\"https://github.com/Quick/Nimble/issues\"\u003efile an issue\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDisabling Objective-C Shorthand\u003c/h2\u003e\u003ca id=\"user-content-disabling-objective-c-shorthand\" class=\"anchor\" aria-label=\"Permalink: Disabling Objective-C Shorthand\" href=\"#disabling-objective-c-shorthand\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble provides a shorthand for expressing expectations using the\n\u003ccode\u003eexpect\u003c/code\u003e function. To disable this shorthand in Objective-C, define the\n\u003ccode\u003eNIMBLE_DISABLE_SHORT_SYNTAX\u003c/code\u003e macro somewhere in your code before\nimporting Nimble:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"#define NIMBLE_DISABLE_SHORT_SYNTAX 1\n\n@import Nimble;\n\nNMB_expect(^{ return seagull.squawk; }, __FILE__, __LINE__).to(NMB_equal(@\u0026quot;Squee!\u0026quot;));\"\u003e\u003cpre\u003e#\u003cspan class=\"pl-k\"\u003edefine\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNIMBLE_DISABLE_SHORT_SYNTAX\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n\n@import Nimble;\n\n\u003cspan class=\"pl-en\"\u003eNMB_expect\u003c/span\u003e(^{ \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e seagull.\u003cspan class=\"pl-smi\"\u003esquawk\u003c/span\u003e; }, __FILE__, __LINE__).to(NMB_equal(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eSquee!\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eDisabling the shorthand is useful if you're testing functions with\nnames that conflict with Nimble functions, such as \u003ccode\u003eexpect\u003c/code\u003e or\n\u003ccode\u003eequal\u003c/code\u003e. If that's not the case, there's no point in disabling the\nshorthand.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsing \u003ccode\u003erequire\u003c/code\u003e to demand that a matcher pass before continuing\u003c/h1\u003e\u003ca id=\"user-content-using-require-to-demand-that-a-matcher-pass-before-continuing\" class=\"anchor\" aria-label=\"Permalink: Using require to demand that a matcher pass before continuing\" href=\"#using-require-to-demand-that-a-matcher-pass-before-continuing\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble 13.1 added the \u003ccode\u003erequire\u003c/code\u003e dsl to complement \u003ccode\u003eexpect\u003c/code\u003e. \u003ccode\u003erequire\u003c/code\u003e\nlooks similar to \u003ccode\u003eexpect\u003c/code\u003e and works with matchers just like \u003ccode\u003eexpect\u003c/code\u003e does. The\ndifference is that \u003ccode\u003erequire\u003c/code\u003e requires that the matcher passes - if the matcher\ndoesn't pass, then \u003ccode\u003erequire\u003c/code\u003e will throw an error. Additionally, if \u003ccode\u003erequire\u003c/code\u003e\ndoes pass, then it'll return the result of running the expression.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example, in testing a function that returns an array, you might need to\nfirst guarantee that there are exactly 3 items in the array before continuing\nto assert on it. Instead of writing code that needlessly duplicates an assertion\nand a conditional like so:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"let collection = myFunction()\nexpect(collection).to(haveCount(3))\nguard collection.count == 3 else { return }\n// ...\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecollection\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emyFunction\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ecollection\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ehaveCount\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eguard\u003c/span\u003e collection\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ecount \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n// ...\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can replace that with:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"let collection = try require(myFunction()).to(haveCount(3))\n// ...\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecollection\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003erequire\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003emyFunction\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ehaveCount\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n// ...\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePolling with \u003ccode\u003erequire\u003c/code\u003e.\u003c/h2\u003e\u003ca id=\"user-content-polling-with-require\" class=\"anchor\" aria-label=\"Permalink: Polling with require.\" href=\"#polling-with-require\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBecause \u003ccode\u003erequire\u003c/code\u003e does everything you can do with \u003ccode\u003eexpect\u003c/code\u003e, you can also use\n\u003ccode\u003erequire\u003c/code\u003e to \u003ca href=\"#polling-expectations\"\u003epoll matchers\u003c/a\u003e using \u003ccode\u003etoEventually\u003c/code\u003e,\n\u003ccode\u003eeventuallyTo\u003c/code\u003e, \u003ccode\u003etoEventuallyNot\u003c/code\u003e, \u003ccode\u003etoNotEventually\u003c/code\u003e, \u003ccode\u003etoNever\u003c/code\u003e, \u003ccode\u003eneverTo\u003c/code\u003e,\n\u003ccode\u003etoAlways\u003c/code\u003e, and \u003ccode\u003ealwaysTo\u003c/code\u003e. These work exactly the same as they do when using\n\u003ccode\u003eexpect\u003c/code\u003e, except that they throw if they fail, and they return the value of the\nexpression when they pass.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsing \u003ccode\u003erequire\u003c/code\u003e with Async expressions and Async matchers\u003c/h2\u003e\u003ca id=\"user-content-using-require-with-async-expressions-and-async-matchers\" class=\"anchor\" aria-label=\"Permalink: Using require with Async expressions and Async matchers\" href=\"#using-require-with-async-expressions-and-async-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003erequire\u003c/code\u003e also works with both async expressions\n(\u003ccode\u003erequire { await someExpression() }.to(...)\u003c/code\u003e), and async matchers\n(\u003ccode\u003erequire().to(someAsyncMatcher())\u003c/code\u003e).\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote that to prevent compiler confusion,\nyou cannot use \u003ccode\u003erequire\u003c/code\u003e with async autoclosures. That is,\n\u003ccode\u003erequire(await someExpression())\u003c/code\u003e will not compile. You can instead either\nmake the closure explicit (\u003ccode\u003erequire { await someExpression() }\u003c/code\u003e), or use the\n\u003ccode\u003erequirea\u003c/code\u003e function, which does accept autoclosures.\nSimilarly, if you ever wish to use the sync version of \u003ccode\u003erequire\u003c/code\u003e when the\ncompiler is trying to force you to use the async version, you can use the\n\u003ccode\u003erequires\u003c/code\u003e function, which only allows synchronous expressions.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsing \u003ccode\u003eunwrap\u003c/code\u003e to replace \u003ccode\u003erequire(...).toNot(beNil())\u003c/code\u003e\u003c/h2\u003e\u003ca id=\"user-content-using-unwrap-to-replace-requiretonotbenil\" class=\"anchor\" aria-label=\"Permalink: Using unwrap to replace require(...).toNot(beNil())\" href=\"#using-unwrap-to-replace-requiretonotbenil\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt's very common to require that a value not be nil. Instead of writing\n\u003ccode\u003etry require(...).toNot(beNil())\u003c/code\u003e, Nimble provides the \u003ccode\u003eunwrap\u003c/code\u003e function. This\nexpression throws an error if the expression evaluates to nil, or returns the\nnon-nil result when it passes. For example:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"let value = try unwrap(nil as Int?) // throws\nlet value = try unwrap(1 as Int?) // returns 1\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eunwrap\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInt\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e // throws\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003evalue\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eunwrap\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eas\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInt\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e // returns 1\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAdditionally, there is also the \u003ccode\u003epollUnwrap\u003c/code\u003e function, which aliases to\n\u003ccode\u003erequire(...).toEventuallyNot(beNil())\u003c/code\u003e. This is extremely useful for verifying\nthat a value that is updated on a background thread was eventually set to a\nnon-nil value.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNote: As with \u003ccode\u003erequire\u003c/code\u003e, there are \u003ccode\u003eunwraps\u003c/code\u003e, \u003ccode\u003eunwrapa\u003c/code\u003e, \u003ccode\u003epollUnwraps\u003c/code\u003e, and\n\u003ccode\u003epollUnwrapa\u003c/code\u003e variants for allowing you to use autoclosures specifically with\nsynchronous or asynchronous code.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eThrowing a Custom Error from Require\u003c/h2\u003e\u003ca id=\"user-content-throwing-a-custom-error-from-require\" class=\"anchor\" aria-label=\"Permalink: Throwing a Custom Error from Require\" href=\"#throwing-a-custom-error-from-require\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eBy default, if the matcher fails in a \u003ccode\u003erequire\u003c/code\u003e, then a \u003ccode\u003eRequireError\u003c/code\u003e will be\nthrown. You can override this behavior and throw a custom error by passing a\nnon-nil \u003ccode\u003eError\u003c/code\u003e value to the \u003ccode\u003ecustomError\u003c/code\u003e parameter:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"try require(1).to(equal(2)) // throws a `RequireError`\ntry require(customError: MyCustomError(), 1).to(equal(2)) // throws a `MyCustomError`\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003erequire\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e // throws a `RequireError`\n\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003erequire\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ecustomError\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMyCustomError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e // throws a `MyCustomError`\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBuilt-in Matcher Functions\u003c/h1\u003e\u003ca id=\"user-content-built-in-matcher-functions\" class=\"anchor\" aria-label=\"Permalink: Built-in Matcher Functions\" href=\"#built-in-matcher-functions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble includes a wide variety of matcher functions.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eType Checking\u003c/h2\u003e\u003ca id=\"user-content-type-checking\" class=\"anchor\" aria-label=\"Permalink: Type Checking\" href=\"#type-checking\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble supports checking the type membership of any kind of object, whether\nObjective-C conformant or not:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nprotocol SomeProtocol{}\nclass SomeClassConformingToProtocol: SomeProtocol{}\nstruct SomeStructConformingToProtocol: SomeProtocol{}\n\n// The following tests pass\nexpect(1).to(beAKindOf(Int.self))\nexpect(\u0026quot;turtle\u0026quot;).to(beAKindOf(String.self))\n\nlet classObject = SomeClassConformingToProtocol()\nexpect(classObject).to(beAKindOf(SomeProtocol.self))\nexpect(classObject).to(beAKindOf(SomeClassConformingToProtocol.self))\nexpect(classObject).toNot(beAKindOf(SomeStructConformingToProtocol.self))\n\nlet structObject = SomeStructConformingToProtocol()\nexpect(structObject).to(beAKindOf(SomeProtocol.self))\nexpect(structObject).to(beAKindOf(SomeStructConformingToProtocol.self))\nexpect(structObject).toNot(beAKindOf(SomeClassConformingToProtocol.self))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eprotocol\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n// The following tests pass\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eInt\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eturtle\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eclassObject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003estructObject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// The following tests pass\nNSMutableArray *array = [NSMutableArray array];\nexpect(array).to(beAKindOf([NSArray class]));\nexpect(@1).toNot(beAKindOf([NSNull class]));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e The following tests pass\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003eNSMutableArray\u003c/span\u003e *array = [\u003cspan class=\"pl-c1\"\u003eNSMutableArray\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003earray\u003c/span\u003e];\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(array).to(beAKindOf([\u003cspan class=\"pl-c1\"\u003eNSArray\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eclass\u003c/span\u003e]));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e).toNot(beAKindOf([\u003cspan class=\"pl-c1\"\u003eNSNull\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003eclass\u003c/span\u003e]));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eObjects can be tested for their exact types using the \u003ccode\u003ebeAnInstanceOf\u003c/code\u003e matcher:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nprotocol SomeProtocol{}\nclass SomeClassConformingToProtocol: SomeProtocol{}\nstruct SomeStructConformingToProtocol: SomeProtocol{}\n\n// Unlike the 'beKindOf' matcher, the 'beAnInstanceOf' matcher only\n// passes if the object is the EXACT type requested. The following\n// tests pass -- note its behavior when working in an inheritance hierarchy.\nexpect(1).to(beAnInstanceOf(Int.self))\nexpect(\u0026quot;turtle\u0026quot;).to(beAnInstanceOf(String.self))\n\nlet classObject = SomeClassConformingToProtocol()\nexpect(classObject).toNot(beAnInstanceOf(SomeProtocol.self))\nexpect(classObject).to(beAnInstanceOf(SomeClassConformingToProtocol.self))\nexpect(classObject).toNot(beAnInstanceOf(SomeStructConformingToProtocol.self))\n\nlet structObject = SomeStructConformingToProtocol()\nexpect(structObject).toNot(beAnInstanceOf(SomeProtocol.self))\nexpect(structObject).to(beAnInstanceOf(SomeStructConformingToProtocol.self))\nexpect(structObject).toNot(beAnInstanceOf(SomeClassConformingToProtocol.self))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eprotocol\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n// Unlike the 'beKindOf' matcher, the 'beAnInstanceOf' matcher only\n// passes if the object is the EXACT type requested. The following\n// tests pass -- note its behavior when working in an inheritance hierarchy.\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eInt\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eturtle\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eclassObject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eclassObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003estructObject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeStructConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estructObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eSomeClassConformingToProtocol\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEquivalence\u003c/h2\u003e\u003ca id=\"user-content-equivalence\" class=\"anchor\" aria-label=\"Permalink: Equivalence\" href=\"#equivalence\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'actual' is equivalent to 'expected':\nexpect(actual).to(equal(expected))\nexpect(actual) == expected\n\n// Passes if 'actual' is not equivalent to 'expected':\nexpect(actual).toNot(equal(expected))\nexpect(actual) != expected\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'actual' is equivalent to 'expected':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e expected\n\n// Passes if 'actual' is not equivalent to 'expected':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e expected\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual' is equivalent to 'expected':\nexpect(actual).to(equal(expected))\n\n// Passes if 'actual' is not equivalent to 'expected':\nexpect(actual).toNot(equal(expected))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is equivalent to 'expected':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(equal(expected))\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is not equivalent to 'expected':\u003c/span\u003e\nexpect(actual).toNot(equal(expected))\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eValues must be \u003ccode\u003eEquatable\u003c/code\u003e, \u003ccode\u003eComparable\u003c/code\u003e, or subclasses of \u003ccode\u003eNSObject\u003c/code\u003e.\n\u003ccode\u003eequal\u003c/code\u003e will always fail when used to compare one or more \u003ccode\u003enil\u003c/code\u003e values.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eIdentity\u003c/h2\u003e\u003ca id=\"user-content-identity\" class=\"anchor\" aria-label=\"Permalink: Identity\" href=\"#identity\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'actual' has the same pointer address as 'expected':\nexpect(actual).to(beIdenticalTo(expected))\nexpect(actual) === expected\n\n// Passes if 'actual' does not have the same pointer address as 'expected':\nexpect(actual).toNot(beIdenticalTo(expected))\nexpect(actual) !== expected\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'actual' has the same pointer address as 'expected':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeIdenticalTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e===\u003c/span\u003e expected\n\n// Passes if 'actual' does not have the same pointer address as 'expected':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeIdenticalTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e!==\u003c/span\u003e expected\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIt is important to remember that \u003ccode\u003ebeIdenticalTo\u003c/code\u003e only makes sense when comparing\ntypes with reference semantics, which have a notion of identity. In Swift,\nthat means types that are defined as a \u003ccode\u003eclass\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThis matcher will not work when comparing types with value semantics such as\nthose defined as a \u003ccode\u003estruct\u003c/code\u003e or \u003ccode\u003eenum\u003c/code\u003e. If you need to compare two value types,\nconsider what it means for instances of your type to be identical. This may mean\ncomparing individual properties or, if it makes sense to do so, conforming your type\nto \u003ccode\u003eEquatable\u003c/code\u003e and using Nimble's equivalence matchers instead.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual' has the same pointer address as 'expected':\nexpect(actual).to(beIdenticalTo(expected));\n\n// Passes if 'actual' does not have the same pointer address as 'expected':\nexpect(actual).toNot(beIdenticalTo(expected));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' has the same pointer address as 'expected':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beIdenticalTo(expected));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' does not have the same pointer address as 'expected':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).toNot(beIdenticalTo(expected));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eComparisons\u003c/h2\u003e\u003ca id=\"user-content-comparisons\" class=\"anchor\" aria-label=\"Permalink: Comparisons\" href=\"#comparisons\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(actual).to(beLessThan(expected))\nexpect(actual) \u0026lt; expected\n\nexpect(actual).to(beLessThanOrEqualTo(expected))\nexpect(actual) \u0026lt;= expected\n\nexpect(actual).to(beGreaterThan(expected))\nexpect(actual) \u0026gt; expected\n\nexpect(actual).to(beGreaterThanOrEqualTo(expected))\nexpect(actual) \u0026gt;= expected\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeLessThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e expected\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeLessThanOrEqualTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026lt;=\u003c/span\u003e expected\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeGreaterThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e expected\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeGreaterThanOrEqualTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u0026gt;=\u003c/span\u003e expected\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(actual).to(beLessThan(expected));\nexpect(actual).to(beLessThanOrEqualTo(expected));\nexpect(actual).to(beGreaterThan(expected));\nexpect(actual).to(beGreaterThanOrEqualTo(expected));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beLessThan(expected));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beLessThanOrEqualTo(expected));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beGreaterThan(expected));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beGreaterThanOrEqualTo(expected));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eValues given to the comparison matchers above must implement\n\u003ccode\u003eComparable\u003c/code\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eBecause of how computers represent floating point numbers, assertions\nthat two floating point numbers be equal will sometimes fail. To express\nthat two numbers should be close to one another within a certain margin\nof error, use \u003ccode\u003ebeCloseTo\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(actual).to(beCloseTo(expected, within: delta))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeCloseTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e within\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e delta\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(actual).to(beCloseTo(expected).within(delta));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beCloseTo(expected).within(delta));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor example, to assert that \u003ccode\u003e10.01\u003c/code\u003e is close to \u003ccode\u003e10\u003c/code\u003e, you can write:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(10.01).to(beCloseTo(10, within: 0.1))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10.01\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeCloseTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e within\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(@(10.01)).to(beCloseTo(@10).within(0.1));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@(\u003cspan class=\"pl-c1\"\u003e10.01\u003c/span\u003e)).to(beCloseTo(@\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e).within(\u003cspan class=\"pl-c1\"\u003e0.1\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere is also an operator shortcut available in Swift:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(actual) ≈ expected\nexpect(actual) ≈ (expected, delta)\n\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e≈\u003c/span\u003e expected\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e≈\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e delta\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e(Type \u003ckbd\u003eoption\u003c/kbd\u003e+\u003ckbd\u003ex\u003c/kbd\u003e to get \u003ccode\u003e≈\u003c/code\u003e on a U.S. keyboard)\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe former version uses the default delta of 0.0001. Here is yet another way to do this:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(actual) ≈ expected ± delta\nexpect(actual) == expected ± delta\n\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e≈\u003c/span\u003e expected \u003cspan class=\"pl-c1\"\u003e±\u003c/span\u003e delta\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e expected \u003cspan class=\"pl-c1\"\u003e±\u003c/span\u003e delta\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e(Type \u003ckbd\u003eoption\u003c/kbd\u003e+\u003ckbd\u003eshift\u003c/kbd\u003e+\u003ckbd\u003e=\u003c/kbd\u003e to get \u003ccode\u003e±\u003c/code\u003e on a U.S. keyboard)\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIf you are comparing arrays of floating point numbers, you'll find the following useful:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect([0.0, 2.0]) ≈ [0.0001, 2.0001]\nexpect([0.0, 2.0]).to(beCloseTo([0.1, 2.1], within: 0.1))\n\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e0.0\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2.0\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e≈\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e0.0001\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2.0001\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e0.0\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2.0\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeCloseTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e0.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e within\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0.1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eValues given to the \u003ccode\u003ebeCloseTo\u003c/code\u003e matcher must conform to \u003ccode\u003eFloatingPoint\u003c/code\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTypes/Classes\u003c/h2\u003e\u003ca id=\"user-content-typesclasses\" class=\"anchor\" aria-label=\"Permalink: Types/Classes\" href=\"#typesclasses\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'instance' is an instance of 'aClass':\nexpect(instance).to(beAnInstanceOf(aClass))\n\n// Passes if 'instance' is an instance of 'aClass' or any of its subclasses:\nexpect(instance).to(beAKindOf(aClass))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'instance' is an instance of 'aClass':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003einstance\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAnInstanceOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eaClass\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'instance' is an instance of 'aClass' or any of its subclasses:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003einstance\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eaClass\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'instance' is an instance of 'aClass':\nexpect(instance).to(beAnInstanceOf(aClass));\n\n// Passes if 'instance' is an instance of 'aClass' or any of its subclasses:\nexpect(instance).to(beAKindOf(aClass));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'instance' is an instance of 'aClass':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(instance).to(beAnInstanceOf(aClass));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'instance' is an instance of 'aClass' or any of its subclasses:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(instance).to(beAKindOf(aClass));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eInstances must be Objective-C objects: subclasses of \u003ccode\u003eNSObject\u003c/code\u003e,\nor Swift objects bridged to Objective-C with the \u003ccode\u003e@objc\u003c/code\u003e prefix.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eFor example, to assert that \u003ccode\u003edolphin\u003c/code\u003e is a kind of \u003ccode\u003eMammal\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect(dolphin).to(beAKindOf(Mammal))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edolphin\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeAKindOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eMammal\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(dolphin).to(beAKindOf([Mammal class]));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(dolphin).to(beAKindOf([Mammal \u003cspan class=\"pl-c1\"\u003eclass\u003c/span\u003e]));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ebeAnInstanceOf\u003c/code\u003e uses the \u003ccode\u003e-[NSObject isMemberOfClass:]\u003c/code\u003e method to\ntest membership. \u003ccode\u003ebeAKindOf\u003c/code\u003e uses \u003ccode\u003e-[NSObject isKindOfClass:]\u003c/code\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTruthiness\u003c/h2\u003e\u003ca id=\"user-content-truthiness\" class=\"anchor\" aria-label=\"Permalink: Truthiness\" href=\"#truthiness\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Passes if 'actual' is not nil, true, or an object with a boolean value of true:\nexpect(actual).to(beTruthy())\n\n// Passes if 'actual' is only true (not nil or an object conforming to Boolean true):\nexpect(actual).to(beTrue())\n\n// Passes if 'actual' is nil, false, or an object with a boolean value of false:\nexpect(actual).to(beFalsy())\n\n// Passes if 'actual' is only false (not nil or an object conforming to Boolean false):\nexpect(actual).to(beFalse())\n\n// Passes if 'actual' is nil:\nexpect(actual).to(beNil())\"\u003e\u003cpre\u003e// Passes if 'actual' is not nil, true, or an object with a boolean value of true:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeTruthy\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' is only true (not nil or an object conforming to Boolean true):\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeTrue\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' is nil, false, or an object with a boolean value of false:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeFalsy\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' is only false (not nil or an object conforming to Boolean false):\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeFalse\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' is nil:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeNil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual' is not nil, true, or an object with a boolean value of true:\nexpect(actual).to(beTruthy());\n\n// Passes if 'actual' is only true (not nil or an object conforming to Boolean true):\nexpect(actual).to(beTrue());\n\n// Passes if 'actual' is nil, false, or an object with a boolean value of false:\nexpect(actual).to(beFalsy());\n\n// Passes if 'actual' is only false (not nil or an object conforming to Boolean false):\nexpect(actual).to(beFalse());\n\n// Passes if 'actual' is nil:\nexpect(actual).to(beNil());\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is not nil, true, or an object with a boolean value of true:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beTruthy());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is only true (not nil or an object conforming to Boolean true):\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beTrue());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is nil, false, or an object with a boolean value of false:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beFalsy());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is only false (not nil or an object conforming to Boolean false):\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beFalse());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is nil:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beNil());\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSwift Assertions\u003c/h2\u003e\u003ca id=\"user-content-swift-assertions\" class=\"anchor\" aria-label=\"Permalink: Swift Assertions\" href=\"#swift-assertions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf you're using Swift, you can use the \u003ccode\u003ethrowAssertion\u003c/code\u003e matcher to check if an assertion is thrown (e.g. \u003ccode\u003efatalError()\u003c/code\u003e). This is made possible by \u003ca href=\"https://github.com/mattgallagher\"\u003e@mattgallagher\u003c/a\u003e's \u003ca href=\"https://github.com/mattgallagher/CwlPreconditionTesting\"\u003eCwlPreconditionTesting\u003c/a\u003e library.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'somethingThatThrows()' throws an assertion, \n// such as by calling 'fatalError()' or if a precondition fails:\nexpect { try somethingThatThrows() }.to(throwAssertion())\nexpect { () -\u0026gt; Void in fatalError() }.to(throwAssertion())\nexpect { precondition(false) }.to(throwAssertion())\n\n// Passes if throwing an NSError is not equal to throwing an assertion:\nexpect { throw NSError(domain: \u0026quot;test\u0026quot;, code: 0, userInfo: nil) }.toNot(throwAssertion())\n\n// Passes if the code after the precondition check is not run:\nvar reachedPoint1 = false\nvar reachedPoint2 = false\nexpect {\n reachedPoint1 = true\n precondition(false, \u0026quot;condition message\u0026quot;)\n reachedPoint2 = true\n}.to(throwAssertion())\n\nexpect(reachedPoint1) == true\nexpect(reachedPoint2) == false\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'somethingThatThrows()' throws an assertion, \n// such as by calling 'fatalError()' or if a precondition fails:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomethingThatThrows\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowAssertion\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eVoid\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efatalError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowAssertion\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eprecondition\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowAssertion\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if throwing an NSError is not equal to throwing an assertion:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNSError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edomain\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003etest\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e code\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e userInfo\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowAssertion\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if the code after the precondition check is not run:\n\u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ereachedPoint1\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ereachedPoint2\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n reachedPoint1 \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eprecondition\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003econdition message\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n reachedPoint2 \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowAssertion\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ereachedPoint1\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ereachedPoint2\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNotes:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThis feature is only available in Swift.\u003c/li\u003e\n\u003cli\u003eThe tvOS simulator is supported, but using a different mechanism, requiring you to turn off the \u003ccode\u003eDebug executable\u003c/code\u003e scheme setting for your tvOS scheme's Test configuration.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSwift Error Handling\u003c/h2\u003e\u003ca id=\"user-content-swift-error-handling\" class=\"anchor\" aria-label=\"Permalink: Swift Error Handling\" href=\"#swift-error-handling\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can use the \u003ccode\u003ethrowError\u003c/code\u003e matcher to check if an error is thrown.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'somethingThatThrows()' throws an 'Error':\nexpect { try somethingThatThrows() }.to(throwError())\n\n// Passes if 'somethingThatThrows()' throws an error within a particular domain:\nexpect { try somethingThatThrows() }.to(throwError { (error: Error) in\n expect(error._domain).to(equal(NSCocoaErrorDomain))\n})\n\n// Passes if 'somethingThatThrows()' throws a particular error enum case:\nexpect { try somethingThatThrows() }.to(throwError(NSCocoaError.PropertyListReadCorruptError))\n\n// Passes if 'somethingThatThrows()' throws an error of a particular type:\nexpect { try somethingThatThrows() }.to(throwError(errorType: NimbleError.self))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'somethingThatThrows()' throws an 'Error':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomethingThatThrows\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'somethingThatThrows()' throws an error within a particular domain:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomethingThatThrows\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowError\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eerror\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eerror\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e_domain\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eNSCocoaErrorDomain\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'somethingThatThrows()' throws a particular error enum case:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomethingThatThrows\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eNSCocoaError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ePropertyListReadCorruptError\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'somethingThatThrows()' throws an error of a particular type:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esomethingThatThrows\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ethrowError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eerrorType\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNimbleError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen working directly with \u003ccode\u003eError\u003c/code\u003e values, using the \u003ccode\u003ematchError\u003c/code\u003e matcher\nallows you to perform certain checks on the error itself without having to\nexplicitly cast the error.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003ematchError\u003c/code\u003e matcher allows you to check whether or not the error:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eis the same \u003cem\u003etype\u003c/em\u003e of error you are expecting.\u003c/li\u003e\n\u003cli\u003erepresents a particular error value that you are expecting.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eThis can be useful when using \u003ccode\u003eResult\u003c/code\u003e or \u003ccode\u003ePromise\u003c/code\u003e types, for example.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nlet actual: Error = ...\n\n// Passes if 'actual' represents any error value from the NimbleErrorEnum type:\nexpect(actual).to(matchError(NimbleErrorEnum.self))\n\n// Passes if 'actual' represents the case 'timeout' from the NimbleErrorEnum type:\nexpect(actual).to(matchError(NimbleErrorEnum.timeout))\n\n// Passes if 'actual' contains an NSError equal to the one provided:\nexpect(actual).to(matchError(NSError(domain: \u0026quot;err\u0026quot;, code: 123, userInfo: nil)))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactual\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eError\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\n\n// Passes if 'actual' represents any error value from the NimbleErrorEnum type:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ematchError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eNimbleErrorEnum\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eself\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' represents the case 'timeout' from the NimbleErrorEnum type:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ematchError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eNimbleErrorEnum\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etimeout\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' contains an NSError equal to the one provided:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ematchError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eNSError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edomain\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eerr\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e code\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e123\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e userInfo\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: This feature is only available in Swift.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eExceptions\u003c/h2\u003e\u003ca id=\"user-content-exceptions\" class=\"anchor\" aria-label=\"Permalink: Exceptions\" href=\"#exceptions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'actual', when evaluated, raises an exception:\nexpect(actual).to(raiseException())\n\n// Passes if 'actual' raises an exception with the given name:\nexpect(actual).to(raiseException(named: name))\n\n// Passes if 'actual' raises an exception with the given name and reason:\nexpect(actual).to(raiseException(named: name, reason: reason))\n\n// Passes if 'actual' raises an exception which passes expectations defined in the given closure:\n// (in this case, if the exception's name begins with \u0026quot;a r\u0026quot;)\nexpect { exception.raise() }.to(raiseException { (exception: NSException) in\n expect(exception.name).to(beginWith(\u0026quot;a r\u0026quot;))\n})\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'actual', when evaluated, raises an exception:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' raises an exception with the given name:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003enamed\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e name\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' raises an exception with the given name and reason:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003enamed\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e name\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e reason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e reason\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' raises an exception which passes expectations defined in the given closure:\n// (in this case, if the exception's name begins with \"a r\")\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e exception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraise\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eraiseException\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexception\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNSException\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexception\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ename\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeginWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ea r\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual', when evaluated, raises an exception:\nexpect(actual).to(raiseException())\n\n// Passes if 'actual' raises an exception with the given name\nexpect(actual).to(raiseException().named(name))\n\n// Passes if 'actual' raises an exception with the given name and reason:\nexpect(actual).to(raiseException().named(name).reason(reason))\n\n// Passes if 'actual' raises an exception and it passes expectations defined in the given block:\n// (in this case, if name begins with \u0026quot;a r\u0026quot;)\nexpect(actual).to(raiseException().satisfyingBlock(^(NSException *exception) {\n expect(exception.name).to(beginWith(@\u0026quot;a r\u0026quot;));\n}));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual', when evaluated, raises an exception:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(raiseException())\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' raises an exception with the given name\u003c/span\u003e\nexpect(actual).to(raiseException().named(name))\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' raises an exception with the given name and reason:\u003c/span\u003e\nexpect(actual).to(raiseException().named(name).reason(reason))\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' raises an exception and it passes expectations defined in the given block:\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e (in this case, if name begins with \"a r\")\u003c/span\u003e\nexpect(actual).to(raiseException().satisfyingBlock(^(\u003cspan class=\"pl-c1\"\u003eNSException\u003c/span\u003e *\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e) {\n \u003cspan class=\"pl-c1\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eexception\u003c/span\u003e.\u003cspan class=\"pl-smi\"\u003ename\u003c/span\u003e).\u003cspan class=\"pl-c1\"\u003eto\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003ebeginWith\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ea r\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n}));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: Swift currently doesn't have exceptions (see \u003ca href=\"https://github.com/Quick/Nimble/issues/220#issuecomment-172667064\" data-hovercard-type=\"issue\" data-hovercard-url=\"/Quick/Nimble/issues/220/hovercard\"\u003e#220\u003c/a\u003e).\nOnly Objective-C code can raise exceptions that Nimble will catch.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCollection Membership\u003c/h2\u003e\u003ca id=\"user-content-collection-membership\" class=\"anchor\" aria-label=\"Permalink: Collection Membership\" href=\"#collection-membership\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if all of the expected values are members of 'actual':\nexpect(actual).to(contain(expected...))\n\n// Passes if 'actual' is empty (i.e. it contains no elements):\nexpect(actual).to(beEmpty())\"\u003e\u003cpre\u003e// Swift\n\n// Passes if all of the expected values are members of 'actual':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' is empty (i.e. it contains no elements):\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeEmpty\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if expected is a member of 'actual':\nexpect(actual).to(contain(expected));\n\n// Passes if 'actual' is empty (i.e. it contains no elements):\nexpect(actual).to(beEmpty());\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if expected is a member of 'actual':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(contain(expected));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' is empty (i.e. it contains no elements):\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beEmpty());\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eIn Swift \u003ccode\u003econtain\u003c/code\u003e takes any number of arguments. The expectation\npasses if all of them are members of the collection. In Objective-C,\n\u003ccode\u003econtain\u003c/code\u003e only takes one argument \u003ca href=\"https://github.com/Quick/Nimble/issues/27\" data-hovercard-type=\"issue\" data-hovercard-url=\"/Quick/Nimble/issues/27/hovercard\"\u003efor now\u003c/a\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eFor example, to assert that a list of sea creature names contains\n\"dolphin\" and \"starfish\":\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nexpect([\u0026quot;whale\u0026quot;, \u0026quot;dolphin\u0026quot;, \u0026quot;starfish\u0026quot;]).to(contain(\u0026quot;dolphin\u0026quot;, \u0026quot;starfish\u0026quot;))\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewhale\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphin\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003estarfish\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003edolphin\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003estarfish\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(@[@\u0026quot;whale\u0026quot;, @\u0026quot;dolphin\u0026quot;, @\u0026quot;starfish\u0026quot;]).to(contain(@\u0026quot;dolphin\u0026quot;));\nexpect(@[@\u0026quot;whale\u0026quot;, @\u0026quot;dolphin\u0026quot;, @\u0026quot;starfish\u0026quot;]).to(contain(@\u0026quot;starfish\u0026quot;));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@[\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewhale\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphin\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003estarfish\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e]).to(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphin\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@[\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewhale\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003edolphin\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e, \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003estarfish\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e]).to(contain(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003estarfish\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003econtain\u003c/code\u003e and \u003ccode\u003ebeEmpty\u003c/code\u003e expect collections to be instances of\n\u003ccode\u003eNSArray\u003c/code\u003e, \u003ccode\u003eNSSet\u003c/code\u003e, or a Swift collection composed of \u003ccode\u003eEquatable\u003c/code\u003e elements.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eTo test whether a set of elements is present at the beginning or end of\nan ordered collection, use \u003ccode\u003ebeginWith\u003c/code\u003e and \u003ccode\u003eendWith\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if the elements in expected appear at the beginning of 'actual':\nexpect(actual).to(beginWith(expected...))\n\n// Passes if the the elements in expected come at the end of 'actual':\nexpect(actual).to(endWith(expected...))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if the elements in expected appear at the beginning of 'actual':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeginWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if the the elements in expected come at the end of 'actual':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eendWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if the elements in expected appear at the beginning of 'actual':\nexpect(actual).to(beginWith(expected));\n\n// Passes if the the elements in expected come at the end of 'actual':\nexpect(actual).to(endWith(expected));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if the elements in expected appear at the beginning of 'actual':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beginWith(expected));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if the the elements in expected come at the end of 'actual':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(endWith(expected));\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003ebeginWith\u003c/code\u003e and \u003ccode\u003eendWith\u003c/code\u003e expect collections to be instances of\n\u003ccode\u003eNSArray\u003c/code\u003e, or ordered Swift collections composed of \u003ccode\u003eEquatable\u003c/code\u003e\nelements.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eLike \u003ccode\u003econtain\u003c/code\u003e, in Objective-C \u003ccode\u003ebeginWith\u003c/code\u003e and \u003ccode\u003eendWith\u003c/code\u003e only support\na single argument \u003ca href=\"https://github.com/Quick/Nimble/issues/27\" data-hovercard-type=\"issue\" data-hovercard-url=\"/Quick/Nimble/issues/27/hovercard\"\u003efor now\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor code that returns collections of complex objects without a strict\nordering, there is the \u003ccode\u003econtainElementSatisfying\u003c/code\u003e matcher:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nstruct Turtle {\n let color: String\n}\n\nlet turtles: [Turtle] = functionThatReturnsSomeTurtlesInAnyOrder()\n\n// This set of matchers passes regardless of whether the array is \n// [{color: \u0026quot;blue\u0026quot;}, {color: \u0026quot;green\u0026quot;}] or [{color: \u0026quot;green\u0026quot;}, {color: \u0026quot;blue\u0026quot;}]:\n\nexpect(turtles).to(containElementSatisfying({ turtle in\n return turtle.color == \u0026quot;green\u0026quot;\n}))\nexpect(turtles).to(containElementSatisfying({ turtle in\n return turtle.color == \u0026quot;blue\u0026quot;\n}, \u0026quot;that is a turtle with color 'blue'\u0026quot;))\n\n// The second matcher will incorporate the provided string in the error message\n// should it fail\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003estruct\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eTurtle\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eturtles\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eTurtle\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunctionThatReturnsSomeTurtlesInAnyOrder\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// This set of matchers passes regardless of whether the array is \n// [{color: \"blue\"}, {color: \"green\"}] or [{color: \"green\"}, {color: \"blue\"}]:\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eturtles\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtainElementSatisfying\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e turtle \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e turtle\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ecolor \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003egreen\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eturtles\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtainElementSatisfying\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e turtle \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e turtle\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ecolor \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eblue\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ethat is a turtle with color 'blue'\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// The second matcher will incorporate the provided string in the error message\n// should it fail\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: in Swift, \u003ccode\u003econtainElementSatisfying\u003c/code\u003e also has a variant that takes in an\nasync function.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n@interface Turtle : NSObject\n@property (nonatomic, readonly, nonnull) NSString *color;\n@end\n\n@implementation Turtle \n@end\n\nNSArray\u0026lt;Turtle *\u0026gt; * __nonnull turtles = functionThatReturnsSomeTurtlesInAnyOrder();\n\n// This set of matchers passes regardless of whether the array is \n// [{color: \u0026quot;blue\u0026quot;}, {color: \u0026quot;green\u0026quot;}] or [{color: \u0026quot;green\u0026quot;}, {color: \u0026quot;blue\u0026quot;}]:\n\nexpect(turtles).to(containElementSatisfying(^BOOL(id __nonnull object) {\n return [[turtle color] isEqualToString:@\u0026quot;green\u0026quot;];\n}));\nexpect(turtles).to(containElementSatisfying(^BOOL(id __nonnull object) {\n return [[turtle color] isEqualToString:@\u0026quot;blue\u0026quot;];\n}));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003e@interface\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eTurtle\u003c/span\u003e : \u003cspan class=\"pl-e\"\u003eNSObject\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003e@property\u003c/span\u003e (\u003cspan class=\"pl-k\"\u003enonatomic\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003ereadonly\u003c/span\u003e, \u003cspan class=\"pl-k\"\u003enonnull\u003c/span\u003e) \u003cspan class=\"pl-c1\"\u003eNSString\u003c/span\u003e *color;\n\u003cspan class=\"pl-k\"\u003e@end\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003e@implementation\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eTurtle\u003c/span\u003e \n\u003cspan class=\"pl-k\"\u003e@end\u003c/span\u003e\n\n\u003cspan class=\"pl-c1\"\u003eNSArray\u003c/span\u003e\u0026lt;Turtle *\u0026gt; * __nonnull turtles = functionThatReturnsSomeTurtlesInAnyOrder();\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e This set of matchers passes regardless of whether the array is \u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e [{color: \"blue\"}, {color: \"green\"}] or [{color: \"green\"}, {color: \"blue\"}]:\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(turtles).to(containElementSatisfying(^\u003cspan class=\"pl-c1\"\u003eBOOL\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e __nonnull object) {\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e [[turtle \u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e] \u003cspan class=\"pl-c1\"\u003eisEqualToString:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003egreen\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\n}));\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(turtles).to(containElementSatisfying(^\u003cspan class=\"pl-c1\"\u003eBOOL\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e __nonnull object) {\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e [[turtle \u003cspan class=\"pl-c1\"\u003ecolor\u003c/span\u003e] \u003cspan class=\"pl-c1\"\u003eisEqualToString:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003eblue\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\n}));\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor asserting on if the given \u003ccode\u003eComparable\u003c/code\u003e value is inside of a \u003ccode\u003eRange\u003c/code\u003e, use the \u003ccode\u003ebeWithin\u003c/code\u003e matcher.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 5 is within the range 1 through 10, inclusive\nexpect(5).to(beWithin(1...10))\n\n// Passes if 5 is not within the range 2 through 4.\nexpect(5).toNot(beWithin(2..\u0026lt;5))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 5 is within the range 1 through 10, inclusive\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeWithin\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 5 is not within the range 2 through 4.\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoNot\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeWithin\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e..\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eStrings\u003c/h2\u003e\u003ca id=\"user-content-strings\" class=\"anchor\" aria-label=\"Permalink: Strings\" href=\"#strings\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'actual' contains 'substring':\nexpect(actual).to(contain(substring))\n\n// Passes if 'actual' begins with 'prefix':\nexpect(actual).to(beginWith(prefix))\n\n// Passes if 'actual' ends with 'suffix':\nexpect(actual).to(endWith(suffix))\n\n// Passes if 'actual' represents the empty string, \u0026quot;\u0026quot;:\nexpect(actual).to(beEmpty())\n\n// Passes if 'actual' matches the regular expression defined in 'expected':\nexpect(actual).to(match(expected))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'actual' contains 'substring':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtain\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003esubstring\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' begins with 'prefix':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeginWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eprefix\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' ends with 'suffix':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eendWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003esuffix\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' represents the empty string, \"\":\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeEmpty\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' matches the regular expression defined in 'expected':\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ematch\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual' contains 'substring':\nexpect(actual).to(contain(expected));\n\n// Passes if 'actual' begins with 'prefix':\nexpect(actual).to(beginWith(prefix));\n\n// Passes if 'actual' ends with 'suffix':\nexpect(actual).to(endWith(suffix));\n\n// Passes if 'actual' represents the empty string, \u0026quot;\u0026quot;:\nexpect(actual).to(beEmpty());\n\n// Passes if 'actual' matches the regular expression defined in 'expected':\nexpect(actual).to(match(expected))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' contains 'substring':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(contain(expected));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' begins with 'prefix':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beginWith(prefix));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' ends with 'suffix':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(endWith(suffix));\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' represents the empty string, \"\":\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(beEmpty());\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' matches the regular expression defined in 'expected':\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(match(expected))\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCollection Elements\u003c/h2\u003e\u003ca id=\"user-content-collection-elements\" class=\"anchor\" aria-label=\"Permalink: Collection Elements\" href=\"#collection-elements\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble provides a means to check that all elements of a collection pass a given expectation.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSwift\u003c/h3\u003e\u003ca id=\"user-content-swift\" class=\"anchor\" aria-label=\"Permalink: Swift\" href=\"#swift\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn Swift, the collection must be an instance of a type conforming to\n\u003ccode\u003eSequence\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Providing a custom function:\nexpect([1, 2, 3, 4]).to(allPass { $0 \u0026lt; 5 })\n\n// Composing the expectation with another matcher:\nexpect([1, 2, 3, 4]).to(allPass(beLessThan(5)))\"\u003e\u003cpre\u003e// Swift\n\n// Providing a custom function:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eallPass\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e $0 \u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Composing the expectation with another matcher:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eallPass\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeLessThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThere are also variants of \u003ccode\u003eallPass\u003c/code\u003e that check against async matchers, and\nthat take in async functions:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Providing a custom function:\nexpect([1, 2, 3, 4]).to(allPass { await asyncFunctionReturningBool($0) })\n\n// Composing the expectation with another matcher:\nexpect([1, 2, 3, 4]).to(allPass(someAsyncMatcher()))\"\u003e\u003cpre\u003e// Swift\n\n// Providing a custom function:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eallPass\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e \u003cspan class=\"pl-en\"\u003easyncFunctionReturningBool\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e$0\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Composing the expectation with another matcher:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eallPass\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esomeAsyncMatcher\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eObjective-C\u003c/h3\u003e\u003ca id=\"user-content-objective-c\" class=\"anchor\" aria-label=\"Permalink: Objective-C\" href=\"#objective-c\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn Objective-C, the collection must be an instance of a type which implements\nthe \u003ccode\u003eNSFastEnumeration\u003c/code\u003e protocol, and whose elements are instances of a type\nwhich subclasses \u003ccode\u003eNSObject\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAdditionally, unlike in Swift, there is no override to specify a custom\nmatcher function.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(@[@1, @2, @3, @4]).to(allPass(beLessThan(@5)));\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(@[@\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, @\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e, @\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e, @\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e]).to(allPass(beLessThan(@\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e)));\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCollection Count\u003c/h2\u003e\u003ca id=\"user-content-collection-count\" class=\"anchor\" aria-label=\"Permalink: Collection Count\" href=\"#collection-count\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// Passes if 'actual' contains the 'expected' number of elements:\nexpect(actual).to(haveCount(expected))\n\n// Passes if 'actual' does _not_ contain the 'expected' number of elements:\nexpect(actual).notTo(haveCount(expected))\"\u003e\u003cpre\u003e// Swift\n\n// Passes if 'actual' contains the 'expected' number of elements:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ehaveCount\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if 'actual' does _not_ contain the 'expected' number of elements:\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003enotTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ehaveCount\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// Passes if 'actual' contains the 'expected' number of elements:\nexpect(actual).to(haveCount(expected))\n\n// Passes if 'actual' does _not_ contain the 'expected' number of elements:\nexpect(actual).notTo(haveCount(expected))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' contains the 'expected' number of elements:\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(haveCount(expected))\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Passes if 'actual' does _not_ contain the 'expected' number of elements:\u003c/span\u003e\nexpect(actual).notTo(haveCount(expected))\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor Swift, the actual value must be an instance of a type conforming to \u003ccode\u003eCollection\u003c/code\u003e.\nFor example, instances of \u003ccode\u003eArray\u003c/code\u003e, \u003ccode\u003eDictionary\u003c/code\u003e, or \u003ccode\u003eSet\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor Objective-C, the actual value must be one of the following classes, or their subclasses:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eNSArray\u003c/code\u003e,\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eNSDictionary\u003c/code\u003e,\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eNSSet\u003c/code\u003e, or\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eNSHashTable\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNotifications\u003c/h2\u003e\u003ca id=\"user-content-notifications\" class=\"anchor\" aria-label=\"Permalink: Notifications\" href=\"#notifications\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nlet testNotification = Notification(name: Notification.Name(\u0026quot;Foo\u0026quot;), object: nil)\n\n// Passes if the closure in expect { ... } posts a notification to the default\n// notification center.\nexpect {\n NotificationCenter.default.post(testNotification)\n}.to(postNotifications(equal([testNotification])))\n\n// Passes if the closure in expect { ... } posts a notification to a given\n// notification center\nlet notificationCenter = NotificationCenter()\nexpect {\n notificationCenter.post(testNotification)\n}.to(postNotifications(equal([testNotification]), from: notificationCenter))\n\n// Passes if the closure in expect { ... } posts a notification with the provided names to a given\n// notification center. Make sure to use this when running tests on Catalina, \n// using DistributedNotificationCenter as there is currently no way \n// of observing notifications without providing specific names.\nlet distributedNotificationCenter = DistributedNotificationCenter()\nexpect {\n distributedNotificationCenter.post(testNotification)\n}.toEventually(postDistributedNotifications(equal([testNotification]),\n from: distributedNotificationCenter,\n names: [testNotification.name]))\"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etestNotification\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNotification\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ename\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNotification\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eName\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eFoo\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e object\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if the closure in expect { ... } posts a notification to the default\n// notification center.\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-smi\"\u003eNotificationCenter\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003edefault\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epost\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epostNotifications\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if the closure in expect { ... } posts a notification to a given\n// notification center\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003enotificationCenter\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNotificationCenter\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n notificationCenter\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epost\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epostNotifications\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e from\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e notificationCenter\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Passes if the closure in expect { ... } posts a notification with the provided names to a given\n// notification center. Make sure to use this when running tests on Catalina, \n// using DistributedNotificationCenter as there is currently no way \n// of observing notifications without providing specific names.\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edistributedNotificationCenter\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eDistributedNotificationCenter\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n distributedNotificationCenter\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epost\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoEventually\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epostDistributedNotifications\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n from\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e distributedNotificationCenter\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n names\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003etestNotification\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ename\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eThis matcher is only available in Swift.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eResult\u003c/h2\u003e\u003ca id=\"user-content-result\" class=\"anchor\" aria-label=\"Permalink: Result\" href=\"#result\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\nlet aResult: Result\u0026lt;String, Error\u0026gt; = .success(\u0026quot;Hooray\u0026quot;) \n\n// passes if result is .success\nexpect(aResult).to(beSuccess()) \n\n// passes if result value is .success and validates Success value\nexpect(aResult).to(beSuccess { value in\n expect(value).to(equal(\u0026quot;Hooray\u0026quot;))\n})\n\n\nenum AnError: Error {\n case somethingHappened\n}\nlet otherResult: Result\u0026lt;String, AnError\u0026gt; = .failure(.somethingHappened) \n\n// passes if result is .failure\nexpect(otherResult).to(beFailure()) \n\n// passes if result value is .failure and validates error\nexpect(otherResult).to(beFailure { error in\n expect(error).to(matchError(AnError.somethingHappened))\n}) \"\u003e\u003cpre\u003e// Swift\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eaResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eResult\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eError\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esuccess\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eHooray\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \n\n// passes if result is .success\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eaResult\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeSuccess\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \n\n// passes if result value is .success and validates Success value\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eaResult\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeSuccess\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e value \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003evalue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eHooray\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n\n\u003cspan class=\"pl-k\"\u003eenum\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAnError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eError\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e somethingHappened\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eotherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eResult\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAnError\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efailure\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esomethingHappened\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \n\n// passes if result is .failure\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eotherResult\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeFailure\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \n\n// passes if result value is .failure and validates error\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eotherResult\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeFailure\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e error \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eerror\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ematchError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eAnError\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esomethingHappened\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003c/pre\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eThis matcher is only available in Swift.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMatching a value to any of a group of matchers\u003c/h2\u003e\u003ca id=\"user-content-matching-a-value-to-any-of-a-group-of-matchers\" class=\"anchor\" aria-label=\"Permalink: Matching a value to any of a group of matchers\" href=\"#matching-a-value-to-any-of-a-group-of-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// passes if actual is either less than 10 or greater than 20\nexpect(actual).to(satisfyAnyOf(beLessThan(10), beGreaterThan(20)))\n\n// can include any number of matchers -- the following will pass\n// **be careful** -- too many matchers can be the sign of an unfocused test\nexpect(6).to(satisfyAnyOf(equal(2), equal(3), equal(4), equal(5), equal(6), equal(7)))\n\n// in Swift you also have the option to use the || operator to achieve a similar function\nexpect(82).to(beLessThan(50) || beGreaterThan(80))\"\u003e\u003cpre\u003e// Swift\n\n// passes if actual is either less than 10 or greater than 20\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esatisfyAnyOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeLessThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ebeGreaterThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e20\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// can include any number of matchers -- the following will pass\n// **be careful** -- too many matchers can be the sign of an unfocused test\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esatisfyAnyOf\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eequal\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e7\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// in Swift you also have the option to use the || operator to achieve a similar function\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e82\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ebeLessThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e50\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e || \u003cspan class=\"pl-en\"\u003ebeGreaterThan\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e80\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: In swift, you can mix and match synchronous and asynchronous matchers\nusing by \u003ccode\u003esatisfyAnyOf\u003c/code\u003e/\u003ccode\u003e||\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\n// passes if actual is either less than 10 or greater than 20\nexpect(actual).to(satisfyAnyOf(beLessThan(@10), beGreaterThan(@20)))\n\n// can include any number of matchers -- the following will pass\n// **be careful** -- too many matchers can be the sign of an unfocused test\nexpect(@6).to(satisfyAnyOf(equal(@2), equal(@3), equal(@4), equal(@5), equal(@6), equal(@7)))\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e passes if actual is either less than 10 or greater than 20\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to(satisfyAnyOf(beLessThan(@\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e), beGreaterThan(@\u003cspan class=\"pl-c1\"\u003e20\u003c/span\u003e)))\n\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e can include any number of matchers -- the following will pass\u003c/span\u003e\n\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e **be careful** -- too many matchers can be the sign of an unfocused test\u003c/span\u003e\nexpect(@\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e).to(satisfyAnyOf(equal(@\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e), equal(@\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e), equal(@\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e), equal(@\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e), equal(@\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e), equal(@\u003cspan class=\"pl-c1\"\u003e7\u003c/span\u003e)))\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNote: This matcher allows you to chain any number of matchers together. This provides flexibility,\nbut if you find yourself chaining many matchers together in one test, consider whether you\ncould instead refactor that single test into multiple, more precisely focused tests for\nbetter coverage.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustom Validation\u003c/h2\u003e\u003ca id=\"user-content-custom-validation\" class=\"anchor\" aria-label=\"Permalink: Custom Validation\" href=\"#custom-validation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\n// passes if .succeeded is returned from the closure\nexpect {\n guard case .enumCaseWithAssociatedValueThatIDontCareAbout = actual else {\n return .failed(reason: \u0026quot;wrong enum case\u0026quot;)\n }\n\n return .succeeded\n}.to(succeed())\n\n// passes if .failed is returned from the closure\nexpect {\n guard case .enumCaseWithAssociatedValueThatIDontCareAbout = actual else {\n return .failed(reason: \u0026quot;wrong enum case\u0026quot;)\n }\n\n return .succeeded\n}.notTo(succeed())\"\u003e\u003cpre\u003e// Swift\n\n// passes if .succeeded is returned from the closure\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eguard\u003c/span\u003e case \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eenumCaseWithAssociatedValueThatIDontCareAbout \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e actual \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efailed\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ereason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewrong enum case\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esucceeded\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eto\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esucceed\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// passes if .failed is returned from the closure\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eguard\u003c/span\u003e case \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eenumCaseWithAssociatedValueThatIDontCareAbout \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e actual \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efailed\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ereason\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewrong enum case\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003esucceeded\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003enotTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esucceed\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe \u003ccode\u003eString\u003c/code\u003e provided with \u003ccode\u003e.failed()\u003c/code\u003e is shown when the test fails.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhen using \u003ccode\u003etoEventually()\u003c/code\u003e be careful not to make state changes or run process intensive code since this closure will be ran many times.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWriting Your Own Matchers\u003c/h1\u003e\u003ca id=\"user-content-writing-your-own-matchers\" class=\"anchor\" aria-label=\"Permalink: Writing Your Own Matchers\" href=\"#writing-your-own-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn Nimble, matchers are Swift functions that take an expected\nvalue and return a \u003ccode\u003eMatcher\u003c/code\u003e closure. Take \u003ccode\u003eequal\u003c/code\u003e, for example:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic func equal\u0026lt;T: Equatable\u0026gt;(expectedValue: T?) -\u0026gt; Matcher\u0026lt;T\u0026gt; {\n // Can be shortened to:\n // Matcher { actual in ... }\n //\n // But shown with types here for clarity.\n return Matcher { (actualExpression: Expression\u0026lt;T\u0026gt;) throws -\u0026gt; MatcherResult in\n let msg = ExpectationMessage.expectedActualValueTo(\u0026quot;equal \u0026lt;\\(expectedValue)\u0026gt;\u0026quot;)\n if let actualValue = try actualExpression.evaluate() {\n return MatcherResult(\n bool: actualValue == expectedValue!,\n message: msg\n )\n } else {\n return MatcherResult(\n status: .fail,\n message: msg.appendedBeNilHint()\n )\n }\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e equal\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eT\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eEquatable\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpectedValue\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n // Can be shortened to:\n // Matcher { actual in ... }\n //\n // But shown with types here for clarity.\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactualExpression\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpression\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcherResult\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emsg\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpectationMessage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eexpectedActualValueTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eequal \u0026lt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003eexpectedValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e actualValue \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n bool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e actualValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e expectedValue!\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e msg\n \u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n status\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efail\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e msg\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappendedBeNilHint\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe return value of a \u003ccode\u003eMatcher\u003c/code\u003e closure is a \u003ccode\u003eMatcherResult\u003c/code\u003e that indicates\nwhether the actual value matches the expectation and what error message to\ndisplay on failure.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eThe actual \u003ccode\u003eequal\u003c/code\u003e matcher function does not match when\n\u003ccode\u003eexpected\u003c/code\u003e are nil; the example above has been edited for brevity.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eSince matchers are just Swift functions, you can define them anywhere:\nat the top of your test file, in a file shared by all of your tests, or\nin an Xcode project you distribute to others.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eIf you write a matcher you think everyone can use, consider adding it\nto Nimble's built-in set of matchers by sending a pull request! Or\ndistribute it yourself via GitHub.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eFor examples of how to write your own matchers, just check out the\n\u003ca href=\"https://github.com/Quick/Nimble/tree/main/Sources/Nimble/Matchers\"\u003e\u003ccode\u003eMatchers\u003c/code\u003e directory\u003c/a\u003e\nto see how Nimble's built-in set of matchers are implemented. You can\nalso check out the tips below.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMatcherResult\u003c/h2\u003e\u003ca id=\"user-content-matcherresult\" class=\"anchor\" aria-label=\"Permalink: MatcherResult\" href=\"#matcherresult\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eMatcherResult\u003c/code\u003e is the return struct that \u003ccode\u003eMatcher\u003c/code\u003e return to indicate\nsuccess and failure. A \u003ccode\u003eMatcherResult\u003c/code\u003e is made up of two values:\n\u003ccode\u003eMatcherStatus\u003c/code\u003e and \u003ccode\u003eExpectationMessage\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eInstead of a boolean, \u003ccode\u003eMatcherStatus\u003c/code\u003e captures a trinary set of values:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic enum MatcherStatus {\n// The matcher \u0026quot;passes\u0026quot; with the given expression\n// eg - expect(1).to(equal(1))\ncase matches\n\n// The matcher \u0026quot;fails\u0026quot; with the given expression\n// eg - expect(1).toNot(equal(1))\ncase doesNotMatch\n\n// The matcher never \u0026quot;passes\u0026quot; with the given expression, even if negated\n// eg - expect(nil as Int?).toNot(equal(1))\ncase fail\n\n// ...\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eenum\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcherStatus\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n// The matcher \"passes\" with the given expression\n// eg - expect(1).to(equal(1))\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e matches\n\n// The matcher \"fails\" with the given expression\n// eg - expect(1).toNot(equal(1))\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e doesNotMatch\n\n// The matcher never \"passes\" with the given expression, even if negated\n// eg - expect(nil as Int?).toNot(equal(1))\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e fail\n\n// ...\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMeanwhile, \u003ccode\u003eExpectationMessage\u003c/code\u003e provides messaging semantics for error reporting.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic indirect enum ExpectationMessage {\n// Emits standard error message:\n// eg - \u0026quot;expected to \u0026lt;string\u0026gt;, got \u0026lt;actual\u0026gt;\u0026quot;\ncase expectedActualValueTo(/* message: */ String)\n\n// Allows any free-form message\n// eg - \u0026quot;\u0026lt;string\u0026gt;\u0026quot;\ncase fail(/* message: */ String)\n\n// ...\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eindirect\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eenum\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpectationMessage\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n// Emits standard error message:\n// eg - \"expected to \u0026lt;string\u0026gt;, got \u0026lt;actual\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e expectedActualValueTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Allows any free-form message\n// eg - \"\u0026lt;string\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e fail\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// ...\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMatchers should usually depend on either \u003ccode\u003e.expectedActualValueTo(..)\u003c/code\u003e or\n\u003ccode\u003e.fail(..)\u003c/code\u003e when reporting errors. Special cases can be used for the other enum\ncases.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFinally, if your Matcher utilizes other Matchers, you can utilize\n\u003ccode\u003e.appended(details:)\u003c/code\u003e and \u003ccode\u003e.appended(message:)\u003c/code\u003e methods to annotate an existing\nerror with more details.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA common message to append is failing on nils. For that, \u003ccode\u003e.appendedBeNilHint()\u003c/code\u003e\ncan be used.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLazy Evaluation\u003c/h2\u003e\u003ca id=\"user-content-lazy-evaluation\" class=\"anchor\" aria-label=\"Permalink: Lazy Evaluation\" href=\"#lazy-evaluation\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eactualExpression\u003c/code\u003e is a lazy, memoized closure around the value provided to the\n\u003ccode\u003eexpect\u003c/code\u003e function. The expression can either be a closure or a value directly\npassed to \u003ccode\u003eexpect(...)\u003c/code\u003e. In order to determine whether that value matches,\ncustom matchers should call \u003ccode\u003eactualExpression.evaluate()\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic func beNil\u0026lt;T\u0026gt;() -\u0026gt; Matcher\u0026lt;T\u0026gt; {\n // Matcher.simpleNilable(..) automatically generates ExpectationMessage for\n // us based on the string we provide to it. Also, the 'Nilable' postfix indicates\n // that this Matcher supports matching against nil actualExpressions, instead of\n // always resulting in a MatcherStatus.fail result -- which is true for\n // Matcher.simple(..)\n return Matcher.simpleNilable(\u0026quot;be nil\u0026quot;) { actualExpression in\n let actualValue = try actualExpression.evaluate()\n return MatcherStatus(bool: actualValue == nil)\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e beNil\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eT\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n // Matcher.simpleNilable(..) automatically generates ExpectationMessage for\n // us based on the string we provide to it. Also, the 'Nilable' postfix indicates\n // that this Matcher supports matching against nil actualExpressions, instead of\n // always resulting in a MatcherStatus.fail result -- which is true for\n // Matcher.simple(..)\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esimpleNilable\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ebe nil\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actualExpression \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactualValue\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherStatus\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ebool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e actualValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn the above example, \u003ccode\u003eactualExpression\u003c/code\u003e is not \u003ccode\u003enil\u003c/code\u003e -- it is a closure\nthat returns a value. The value it returns, which is accessed via the\n\u003ccode\u003eevaluate()\u003c/code\u003e method, may be \u003ccode\u003enil\u003c/code\u003e. If that value is \u003ccode\u003enil\u003c/code\u003e, the \u003ccode\u003ebeNil\u003c/code\u003e\nmatcher function returns \u003ccode\u003etrue\u003c/code\u003e, indicating that the expectation passed.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eType Checking via Swift Generics\u003c/h2\u003e\u003ca id=\"user-content-type-checking-via-swift-generics\" class=\"anchor\" aria-label=\"Permalink: Type Checking via Swift Generics\" href=\"#type-checking-via-swift-generics\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUsing Swift's generics, matchers can constrain the type of the actual value\npassed to the \u003ccode\u003eexpect\u003c/code\u003e function by modifying the return type.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example, the following matcher, \u003ccode\u003ehaveDescription\u003c/code\u003e, only accepts actual\nvalues that implement the \u003ccode\u003ePrintable\u003c/code\u003e protocol. It checks their \u003ccode\u003edescription\u003c/code\u003e\nagainst the one provided to the matcher function, and passes if they are the same:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic func haveDescription(description: String) -\u0026gt; Matcher\u0026lt;Printable?\u0026gt; {\n return Matcher.simple(\u0026quot;have description\u0026quot;) { actual in\n return MatcherStatus(bool: actual.evaluate().description == description)\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e haveDescription\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edescription\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003ePrintable\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esimple\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ehave description\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actual \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherStatus\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ebool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e actual\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003edescription \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e description\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCustomizing Failure Messages\u003c/h2\u003e\u003ca id=\"user-content-customizing-failure-messages\" class=\"anchor\" aria-label=\"Permalink: Customizing Failure Messages\" href=\"#customizing-failure-messages\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen using \u003ccode\u003eMatcher.simple(..)\u003c/code\u003e or \u003ccode\u003eMatcher.simpleNilable(..)\u003c/code\u003e, Nimble\noutputs the following failure message when an expectation fails:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// where `message` is the first string argument and\n// `actual` is the actual value received in `expect(..)`\n\u0026quot;expected to \\(message), got \u0026lt;\\(actual)\u0026gt;\u0026quot;\"\u003e\u003cpre\u003e// where `message` is the first string argument and\n// `actual` is the actual value received in `expect(..)`\n\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eexpected to \u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003emessage\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e, got \u0026lt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003eactual\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can customize this message by modifying the way you create a \u003ccode\u003eMatcher\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eBasic Customization\u003c/h3\u003e\u003ca id=\"user-content-basic-customization\" class=\"anchor\" aria-label=\"Permalink: Basic Customization\" href=\"#basic-customization\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor slightly more complex error messaging, receive the created failure message\nwith \u003ccode\u003eMatcher.define(..)\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\npublic func equal\u0026lt;T: Equatable\u0026gt;(_ expectedValue: T?) -\u0026gt; Matcher\u0026lt;T\u0026gt; {\n return Matcher.define(\u0026quot;equal \u0026lt;\\(stringify(expectedValue))\u0026gt;\u0026quot;) { actualExpression, msg in\n let actualValue = try actualExpression.evaluate()\n let matches = actualValue == expectedValue \u0026amp;\u0026amp; expectedValue != nil\n if expectedValue == nil || actualValue == nil {\n if expectedValue == nil \u0026amp;\u0026amp; actualValue != nil {\n return MatcherResult(\n status: .fail,\n message: msg.appendedBeNilHint()\n )\n }\n return MatcherResult(status: .fail, message: msg)\n }\n return MatcherResult(bool: matches, message: msg)\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e equal\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eT\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eEquatable\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e_ expectedValue\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eT\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003edefine\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eequal \u0026lt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003estringify\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpectedValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e msg \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactualValue\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ematches\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e actualValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e expectedValue \u0026amp;\u0026amp; expectedValue \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e expectedValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e || actualValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e expectedValue \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e \u0026amp;\u0026amp; actualValue \u003cspan class=\"pl-c1\"\u003e!=\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003enil\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n status\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efail\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e msg\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappendedBeNilHint\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estatus\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efail\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e msg\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ebool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e matches\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e msg\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn the example above, \u003ccode\u003emsg\u003c/code\u003e is defined based on the string given to\n\u003ccode\u003eMatcher.define\u003c/code\u003e. The code looks akin to:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nlet msg = ExpectationMessage.expectedActualValueTo(\u0026quot;equal \u0026lt;\\(stringify(expectedValue))\u0026gt;\u0026quot;)\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emsg\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpectationMessage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eexpectedActualValueTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eequal \u0026lt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003e\u003cspan class=\"pl-en\"\u003estringify\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpectedValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFull Customization\u003c/h3\u003e\u003ca id=\"user-content-full-customization\" class=\"anchor\" aria-label=\"Permalink: Full Customization\" href=\"#full-customization\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo fully customize the behavior of the Matcher, use the overload that expects\na \u003ccode\u003eMatcherResult\u003c/code\u003e to be returned.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAlong with \u003ccode\u003eMatcherResult\u003c/code\u003e, there are other \u003ccode\u003eExpectationMessage\u003c/code\u003e enum values you can use:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public indirect enum ExpectationMessage {\n// Emits standard error message:\n// eg - \u0026quot;expected to \u0026lt;message\u0026gt;, got \u0026lt;actual\u0026gt;\u0026quot;\ncase expectedActualValueTo(/* message: */ String)\n\n// Allows any free-form message\n// eg - \u0026quot;\u0026lt;message\u0026gt;\u0026quot;\ncase fail(/* message: */ String)\n\n// Emits standard error message with a custom actual value instead of the default.\n// eg - \u0026quot;expected to \u0026lt;message\u0026gt;, got \u0026lt;actual\u0026gt;\u0026quot;\ncase expectedCustomValueTo(/* message: */ String, /* actual: */ String)\n\n// Emits standard error message without mentioning the actual value\n// eg - \u0026quot;expected to \u0026lt;message\u0026gt;\u0026quot;\ncase expectedTo(/* message: */ String)\n\n// ...\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eindirect\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eenum\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpectationMessage\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n// Emits standard error message:\n// eg - \"expected to \u0026lt;message\u0026gt;, got \u0026lt;actual\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e expectedActualValueTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Allows any free-form message\n// eg - \"\u0026lt;message\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e fail\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Emits standard error message with a custom actual value instead of the default.\n// eg - \"expected to \u0026lt;message\u0026gt;, got \u0026lt;actual\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e expectedCustomValueTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e /* actual: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// Emits standard error message without mentioning the actual value\n// eg - \"expected to \u0026lt;message\u0026gt;\"\n\u003cspan class=\"pl-k\"\u003ecase\u003c/span\u003e expectedTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e/* message: */ \u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n\n// ...\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor matchers that compose other matchers, there are a handful of helper\nfunctions to annotate messages.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eappended(message: String)\u003c/code\u003e is used to append to the original failure message:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// produces \u0026quot;expected to be true, got \u0026lt;actual\u0026gt; (use beFalse() for inverse)\u0026quot;\n// appended message do show up inline in Xcode.\n.expectedActualValueTo(\u0026quot;be true\u0026quot;).appended(message: \u0026quot; (use beFalse() for inverse)\u0026quot;)\"\u003e\u003cpre\u003e// produces \"expected to be true, got \u0026lt;actual\u0026gt; (use beFalse() for inverse)\"\n// appended message do show up inline in Xcode.\n\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eexpectedActualValueTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ebe true\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappended\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003emessage\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e (use beFalse() for inverse)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor a more comprehensive message that spans multiple lines, use\n\u003ccode\u003eappended(details: String)\u003c/code\u003e instead:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// produces \u0026quot;expected to be true, got \u0026lt;actual\u0026gt;\\n\\nuse beFalse() for inverse\\nor use beNil()\u0026quot;\n// details do not show inline in Xcode, but do show up in test logs.\n.expectedActualValueTo(\u0026quot;be true\u0026quot;).appended(details: \u0026quot;use beFalse() for inverse\\nor use beNil()\u0026quot;)\"\u003e\u003cpre\u003e// produces \"expected to be true, got \u0026lt;actual\u0026gt;\\n\\nuse beFalse() for inverse\\nor use beNil()\"\n// details do not show inline in Xcode, but do show up in test logs.\n\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eexpectedActualValueTo\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ebe true\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappended\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edetails\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003euse beFalse() for inverse\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\\n\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eor use beNil()\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAsynchronous Matchers\u003c/h2\u003e\u003ca id=\"user-content-asynchronous-matchers\" class=\"anchor\" aria-label=\"Permalink: Asynchronous Matchers\" href=\"#asynchronous-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo write matchers against async expressions, return an instance of\n\u003ccode\u003eAsyncMatcher\u003c/code\u003e. The closure passed to \u003ccode\u003eAsyncMatcher\u003c/code\u003e is async, and the\nexpression you evaluate is also asynchronous and needs to be awaited on.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nactor CallRecorder\u0026lt;Arguments\u0026gt; {\n private(set) var calls: [Arguments] = []\n \n func record(call: Arguments) {\n calls.append(call)\n }\n}\n\nfunc beCalled\u0026lt;Argument: Equatable\u0026gt;(with arguments: Argument) -\u0026gt; AsyncMatcher\u0026lt;CallRecorder\u0026lt;Argument\u0026gt;\u0026gt; {\n AsyncMatcher { (expression: AsyncExpression\u0026lt;CallRecorder\u0026lt;Argument\u0026gt;\u0026gt;) in\n let message = ExpectationMessage.expectedActualValueTo(\u0026quot;be called with \\(arguments)\u0026quot;)\n guard let calls = try await expression.evaluate()?.calls else {\n return MatcherResult(status: .fail, message: message.appendedBeNilHint())\n }\n \n return MatcherResult(bool: calls.contains(args), message: message.appended(details: \u0026quot;called with \\(calls)\u0026quot;))\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eactor\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eCallRecorder\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eArguments\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eprivate\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eset\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-c1\"\u003ecalls\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eArguments\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\n \n \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e record\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ecall\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArguments\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n calls\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappend\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ecall\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e beCalled\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eArgument\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eEquatable\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ewith arguments\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArgument\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAsyncMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eCallRecorder\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eArgument\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eAsyncMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpression\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAsyncExpression\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eCallRecorder\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eArgument\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emessage\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eExpectationMessage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eexpectedActualValueTo\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ebe called with \u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003earguments\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eguard\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e calls \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eawait\u003c/span\u003e expression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-c1\"\u003e?\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003ecalls \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003estatus\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efail\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappendedBeNilHint\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherResult\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ebool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e calls\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003econtains\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eargs\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eappended\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003edetails\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ecalled with \u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003ecalls\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn this example, we created an actor to act as an object to record calls to an\nasync function. Then, we created the \u003ccode\u003ebeCalled(with:)\u003c/code\u003e matcher to check if the\nactor has received a call with the given arguments.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eSupporting Objective-C\u003c/h2\u003e\u003ca id=\"user-content-supporting-objective-c\" class=\"anchor\" aria-label=\"Permalink: Supporting Objective-C\" href=\"#supporting-objective-c\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo use a custom matcher written in Swift from Objective-C, you'll have\nto extend the \u003ccode\u003eNMBMatcher\u003c/code\u003e class, adding a new class method for your\ncustom matcher. The example below defines the class method\n\u003ccode\u003e+[NMBMatcher beNilMatcher]\u003c/code\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Swift\n\nextension NMBMatcher {\n @objc public class func beNilMatcher() -\u0026gt; NMBMatcher {\n return NMBMatcher { actualExpression in\n return try beNil().satisfies(actualExpression).toObjectiveC()\n }\n }\n}\"\u003e\u003cpre\u003e// Swift\n\n\u003cspan class=\"pl-k\"\u003eextension\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e@\u003cspan class=\"pl-smi\"\u003eobjc\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e beNilMatcher\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actualExpression \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ebeNil\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esatisfies\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eactualExpression\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoObjectiveC\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe above allows you to use the matcher from Objective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(actual).to([NMBMatcher beNilMatcher]());\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(actual).to([NMBMatcher \u003cspan class=\"pl-c1\"\u003ebeNilMatcher\u003c/span\u003e]());\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo make the syntax easier to use, define a C function that calls the\nclass method:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nFOUNDATION_EXPORT NMBMatcher *beNil() {\n return [NMBMatcher beNilMatcher];\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\nFOUNDATION_EXPORT NMBMatcher *\u003cspan class=\"pl-en\"\u003ebeNil\u003c/span\u003e() {\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e [NMBMatcher \u003cspan class=\"pl-c1\"\u003ebeNilMatcher\u003c/span\u003e];\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eProperly Handling \u003ccode\u003enil\u003c/code\u003e in Objective-C Matchers\u003c/h3\u003e\u003ca id=\"user-content-properly-handling-nil-in-objective-c-matchers\" class=\"anchor\" aria-label=\"Permalink: Properly Handling nil in Objective-C Matchers\" href=\"#properly-handling-nil-in-objective-c-matchers\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen supporting Objective-C, make sure you handle \u003ccode\u003enil\u003c/code\u003e appropriately.\nLike \u003ca href=\"https://github.com/pivotal/cedar/issues/100\" data-hovercard-type=\"issue\" data-hovercard-url=\"/cedarbdd/cedar/issues/100/hovercard\"\u003eCedar\u003c/a\u003e,\n\u003cstrong\u003emost matchers do not match with nil\u003c/strong\u003e. This is to bring prevent test\nwriters from being surprised by \u003ccode\u003enil\u003c/code\u003e values where they did not expect\nthem.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eNimble provides the \u003ccode\u003ebeNil\u003c/code\u003e matcher function for test writer that want\nto make expectations on \u003ccode\u003enil\u003c/code\u003e objects:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Objective-C\n\nexpect(nil).to(equal(nil)); // fails\nexpect(nil).to(beNil()); // passes\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Objective-C\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003enil\u003c/span\u003e).to(equal(\u003cspan class=\"pl-c1\"\u003enil\u003c/span\u003e)); \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e fails\u003c/span\u003e\n\u003cspan class=\"pl-en\"\u003eexpect\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003enil\u003c/span\u003e).to(beNil()); \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e passes\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf your matcher does not want to match with nil, you use \u003ccode\u003eMatcher.define\u003c/code\u003e or \u003ccode\u003eMatcher.simple\u003c/code\u003e.\nUsing those factory methods will automatically generate expected value failure messages when they're nil.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public func beginWith\u0026lt;S: Sequence\u0026gt;(_ startingElement: S.Element) -\u0026gt; Matcher\u0026lt;S\u0026gt; where S.Element: Equatable {\n return Matcher.simple(\u0026quot;begin with \u0026lt;\\(startingElement)\u0026gt;\u0026quot;) { actualExpression in\n guard let actualValue = try actualExpression.evaluate() else { return .fail }\n\n var actualGenerator = actualValue.makeIterator()\n return MatcherStatus(bool: actualGenerator.next() == startingElement)\n }\n}\n\nextension NMBMatcher {\n @objc public class func beginWithMatcher(_ expected: Any) -\u0026gt; NMBMatcher {\n return NMBMatcher { actualExpression in\n let actual = try actualExpression.evaluate()\n let expr = actualExpression.cast { $0 as? NMBOrderedCollection }\n return try beginWith(expected).satisfies(expr).toObjectiveC()\n }\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e beginWith\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003eS\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSequence\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e_ startingElement\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eS\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eElement\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"pl-smi\"\u003eS\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ewhere\u003c/span\u003e S\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eElement\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eEquatable\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMatcher\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esimple\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ebegin with \u0026lt;\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003estartingElement\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actualExpression \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eguard\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e actualValue \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003efail \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n \u003cspan class=\"pl-k\"\u003evar\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactualGenerator\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e actualValue\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003emakeIterator\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMatcherStatus\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003ebool\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e actualGenerator\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003enext\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e==\u003c/span\u003e startingElement\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\n\u003cspan class=\"pl-k\"\u003eextension\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-s1\"\u003e@\u003cspan class=\"pl-smi\"\u003eobjc\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e beginWithMatcher\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e_ expected\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAny\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eNMBMatcher\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e actualExpression \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eactual\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003eevaluate\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eexpr\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e actualExpression\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003ecast\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e $0 \u003cspan class=\"pl-k\"\u003eas?\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNMBOrderedCollection\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e\u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ebeginWith\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpected\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003esatisfies\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eexpr\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003etoObjectiveC\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstalling Nimble\u003c/h1\u003e\u003ca id=\"user-content-installing-nimble\" class=\"anchor\" aria-label=\"Permalink: Installing Nimble\" href=\"#installing-nimble\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003eNimble can be used on its own, or in conjunction with its sister\nproject, \u003ca href=\"https://github.com/Quick/Quick\"\u003eQuick\u003c/a\u003e. To install both\nQuick and Nimble, follow \u003ca href=\"https://github.com/Quick/Quick/blob/main/Documentation/en-us/InstallingQuick.md\"\u003ethe installation instructions in the Quick\nDocumentation\u003c/a\u003e.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp dir=\"auto\"\u003eNimble can currently be installed in one of two ways: using CocoaPods, or with\ngit submodules.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstalling Nimble as a Submodule\u003c/h2\u003e\u003ca id=\"user-content-installing-nimble-as-a-submodule\" class=\"anchor\" aria-label=\"Permalink: Installing Nimble as a Submodule\" href=\"#installing-nimble-as-a-submodule\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo use Nimble as a submodule to test your macOS, iOS or tvOS applications, follow\nthese 4 easy steps:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eClone the Nimble repository\u003c/li\u003e\n\u003cli\u003eAdd Nimble.xcodeproj to the Xcode workspace for your project\u003c/li\u003e\n\u003cli\u003eLink Nimble.framework to your test target\u003c/li\u003e\n\u003cli\u003eStart writing expectations!\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003eFor more detailed instructions on each of these steps,\nread \u003ca href=\"https://github.com/Quick/Quick#how-to-install-quick\"\u003eHow to Install Quick\u003c/a\u003e.\nIgnore the steps involving adding Quick to your project in order to\ninstall just Nimble.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstalling Nimble via CocoaPods\u003c/h2\u003e\u003ca id=\"user-content-installing-nimble-via-cocoapods\" class=\"anchor\" aria-label=\"Permalink: Installing Nimble via CocoaPods\" href=\"#installing-nimble-via-cocoapods\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo use Nimble in CocoaPods to test your macOS, iOS, tvOS or watchOS applications, add\nNimble to your podfile and add the \u003ccode\u003euse_frameworks!\u003c/code\u003e line to enable Swift\nsupport for CocoaPods.\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-ruby notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"platform :ios, '8.0'\n\nsource 'https://github.com/CocoaPods/Specs.git'\n\n# Whatever pods you need for your app go here\n\ntarget 'YOUR_APP_NAME_HERE_Tests', :exclusive =\u0026gt; true do\n use_frameworks!\n pod 'Nimble'\nend\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003eplatform\u003c/span\u003e \u003cspan class=\"pl-pds\"\u003e:ios\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'8.0'\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003esource\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'https://github.com/CocoaPods/Specs.git'\u003c/span\u003e\n\n\u003cspan class=\"pl-c\"\u003e# Whatever pods you need for your app go here\u003c/span\u003e\n\n\u003cspan class=\"pl-en\"\u003etarget\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'YOUR_APP_NAME_HERE_Tests'\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-pds\"\u003e:exclusive\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e \u003cspan class=\"pl-k\"\u003edo\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003euse_frameworks!\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003epod\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'Nimble'\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003eend\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFinally run \u003ccode\u003epod install\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstalling Nimble via Swift Package Manager\u003c/h2\u003e\u003ca id=\"user-content-installing-nimble-via-swift-package-manager\" class=\"anchor\" aria-label=\"Permalink: Installing Nimble via Swift Package Manager\" href=\"#installing-nimble-via-swift-package-manager\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eXcode\u003c/h3\u003e\u003ca id=\"user-content-xcode\" class=\"anchor\" aria-label=\"Permalink: Xcode\" href=\"#xcode\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo install Nimble via Xcode's Swift Package Manager Integration:\nSelect your project configuration, then the project tab, then the Package\nDependencies tab. Click on the \"plus\" button at the bottom of the list,\nthen follow the wizard to add Quick to your project. Specify\n\u003ccode\u003ehttps://github.com/Quick/Nimble.git\u003c/code\u003e as the url, and be sure to add\nNimble as a dependency of your unit test target, not your app target.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePackage.Swift\u003c/h3\u003e\u003ca id=\"user-content-packageswift\" class=\"anchor\" aria-label=\"Permalink: Package.Swift\" href=\"#packageswift\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eTo use Nimble with Swift Package Manager to test your applications, add Nimble\nto your \u003ccode\u003ePackage.Swift\u003c/code\u003e and link it with your test target:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// swift-tools-version:5.5\n\nimport PackageDescription\n\nlet package = Package(\n name: \u0026quot;MyAwesomeLibrary\u0026quot;,\n products: [\n // ...\n ],\n dependencies: [\n // ...\n .package(url: \u0026quot;https://github.com/Quick/Nimble.git\u0026quot;, from: \u0026quot;12.0.0\u0026quot;),\n ],\n targets: [\n // Targets are the basic building blocks of a package. A target can define a module or a test suite.\n // Targets can depend on other targets in this package, and on products in packages this package depends on.\n .target(\n name: \u0026quot;MyAwesomeLibrary\u0026quot;,\n dependencies: ...),\n .testTarget(\n name: \u0026quot;MyAwesomeLibraryTests\u0026quot;,\n dependencies: [\u0026quot;MyAwesomeLibrary\u0026quot;, \u0026quot;Nimble\u0026quot;]),\n ]\n)\"\u003e\u003cpre\u003e// swift-tools-version:5.5\n\n\u003cspan class=\"pl-k\"\u003eimport\u003c/span\u003e PackageDescription\n\n\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003e\u003cspan class=\"pl-k\"\u003epackage\u003c/span\u003e\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003ePackage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n name\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMyAwesomeLibrary\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n products\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\n // ...\n \u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n dependencies\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\n // ...\n \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-k\"\u003epackage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eurl\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ehttps://github.com/Quick/Nimble.git\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e from\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e12.0.0\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n targets\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\n // Targets are the basic building blocks of a package. A target can define a module or a test suite.\n // Targets can depend on other targets in this package, and on products in packages this package depends on.\n \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etarget\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n name\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMyAwesomeLibrary\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n dependencies\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e...\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003etestTarget\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\n name\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMyAwesomeLibraryTests\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n dependencies\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e[\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eMyAwesomeLibrary\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eNimble\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e]\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePlease note that if you install Nimble using Swift Package Manager, then \u003ccode\u003eraiseException\u003c/code\u003e is not available.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eUsing Nimble without XCTest\u003c/h2\u003e\u003ca id=\"user-content-using-nimble-without-xctest\" class=\"anchor\" aria-label=\"Permalink: Using Nimble without XCTest\" href=\"#using-nimble-without-xctest\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eNimble is integrated with XCTest to allow it work well when used in Xcode test\nbundles, however it can also be used in a standalone app. After installing\nNimble using one of the above methods, there are two additional steps required\nto make this work.\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eCreate a custom assertion handler and assign an instance of it to the\nglobal \u003ccode\u003eNimbleAssertionHandler\u003c/code\u003e variable. For example:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"class MyAssertionHandler : AssertionHandler {\n func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) {\n if (!assertion) {\n print(\u0026quot;Expectation failed: \\(message.stringValue)\u0026quot;)\n }\n }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eMyAssertionHandler\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAssertionHandler\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003efunc\u003c/span\u003e assert\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eassertion\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eBool\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eFailureMessage\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e location\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eSourceLocation\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e!assertion\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n \u003cspan class=\"pl-en\"\u003eprint\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003eExpectation failed: \u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e\\(\u003c/span\u003emessage\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003estringValue\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// Somewhere before you use any assertions\nNimbleAssertionHandler = MyAssertionHandler()\"\u003e\u003cpre\u003e// Somewhere before you use any assertions\nNimbleAssertionHandler \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMyAssertionHandler\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003col start=\"2\" dir=\"auto\"\u003e\n\u003cli\u003eAdd a post-build action to fix an issue with the Swift XCTest support\nlibrary being unnecessarily copied into your app\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eEdit your scheme in Xcode, and navigate to Build -\u0026gt; Post-actions\u003c/li\u003e\n\u003cli\u003eClick the \"+\" icon and select \"New Run Script Action\"\u003c/li\u003e\n\u003cli\u003eOpen the \"Provide build settings from\" dropdown and select your target\u003c/li\u003e\n\u003cli\u003eEnter the following script contents:\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"rm \u0026quot;${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib\u0026quot;\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003erm \"${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib\"\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can now use Nimble assertions in your code and handle failures as you see\nfit.\u003c/p\u003e\n\u003c/article\u003e","loaded":true,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":[{"level":1,"text":"Nimble","anchor":"nimble","htmlText":"Nimble"},{"level":1,"text":"How to Use Nimble","anchor":"how-to-use-nimble","htmlText":"How to Use Nimble"},{"level":1,"text":"Some Background: Expressing Outcomes Using Assertions in XCTest","anchor":"some-background-expressing-outcomes-using-assertions-in-xctest","htmlText":"Some Background: Expressing Outcomes Using Assertions in XCTest"},{"level":1,"text":"Nimble: Expectations Using expect(...).to","anchor":"nimble-expectations-using-expectto","htmlText":"Nimble: Expectations Using expect(...).to"},{"level":2,"text":"Custom Failure Messages","anchor":"custom-failure-messages","htmlText":"Custom Failure Messages"},{"level":2,"text":"Type Safety","anchor":"type-safety","htmlText":"Type Safety"},{"level":2,"text":"Operator Overloads","anchor":"operator-overloads","htmlText":"Operator Overloads"},{"level":2,"text":"Lazily Computed Values","anchor":"lazily-computed-values","htmlText":"Lazily Computed Values"},{"level":2,"text":"C Primitives","anchor":"c-primitives","htmlText":"C Primitives"},{"level":2,"text":"Async/Await Support","anchor":"asyncawait-support","htmlText":"Async/Await Support"},{"level":3,"text":"Async Matchers","anchor":"async-matchers","htmlText":"Async Matchers"},{"level":2,"text":"Polling Expectations","anchor":"polling-expectations","htmlText":"Polling Expectations"},{"level":3,"text":"Using Polling Expectations in Async Tests","anchor":"using-polling-expectations-in-async-tests","htmlText":"Using Polling Expectations in Async Tests"},{"level":3,"text":"Verifying a Matcher will Never or Always Match","anchor":"verifying-a-matcher-will-never-or-always-match","htmlText":"Verifying a Matcher will Never or Always Match"},{"level":3,"text":"Waiting for a Callback to be Called","anchor":"waiting-for-a-callback-to-be-called","htmlText":"Waiting for a Callback to be Called"},{"level":3,"text":"Changing the Timeout and Polling Intervals","anchor":"changing-the-timeout-and-polling-intervals","htmlText":"Changing the Timeout and Polling Intervals"},{"level":3,"text":"Changing default Timeout and Poll Intervals","anchor":"changing-default-timeout-and-poll-intervals","htmlText":"Changing default Timeout and Poll Intervals"},{"level":4,"text":"Quick","anchor":"quick","htmlText":"Quick"},{"level":4,"text":"XCTest","anchor":"xctest","htmlText":"XCTest"},{"level":2,"text":"Objective-C Support","anchor":"objective-c-support","htmlText":"Objective-C Support"},{"level":2,"text":"Disabling Objective-C Shorthand","anchor":"disabling-objective-c-shorthand","htmlText":"Disabling Objective-C Shorthand"},{"level":1,"text":"Using require to demand that a matcher pass before continuing","anchor":"using-require-to-demand-that-a-matcher-pass-before-continuing","htmlText":"Using require to demand that a matcher pass before continuing"},{"level":2,"text":"Polling with require.","anchor":"polling-with-require","htmlText":"Polling with require."},{"level":2,"text":"Using require with Async expressions and Async matchers","anchor":"using-require-with-async-expressions-and-async-matchers","htmlText":"Using require with Async expressions and Async matchers"},{"level":2,"text":"Using unwrap to replace require(...).toNot(beNil())","anchor":"using-unwrap-to-replace-requiretonotbenil","htmlText":"Using unwrap to replace require(...).toNot(beNil())"},{"level":2,"text":"Throwing a Custom Error from Require","anchor":"throwing-a-custom-error-from-require","htmlText":"Throwing a Custom Error from Require"},{"level":1,"text":"Built-in Matcher Functions","anchor":"built-in-matcher-functions","htmlText":"Built-in Matcher Functions"},{"level":2,"text":"Type Checking","anchor":"type-checking","htmlText":"Type Checking"},{"level":2,"text":"Equivalence","anchor":"equivalence","htmlText":"Equivalence"},{"level":2,"text":"Identity","anchor":"identity","htmlText":"Identity"},{"level":2,"text":"Comparisons","anchor":"comparisons","htmlText":"Comparisons"},{"level":2,"text":"Types/Classes","anchor":"typesclasses","htmlText":"Types/Classes"},{"level":2,"text":"Truthiness","anchor":"truthiness","htmlText":"Truthiness"},{"level":2,"text":"Swift Assertions","anchor":"swift-assertions","htmlText":"Swift Assertions"},{"level":2,"text":"Swift Error Handling","anchor":"swift-error-handling","htmlText":"Swift Error Handling"},{"level":2,"text":"Exceptions","anchor":"exceptions","htmlText":"Exceptions"},{"level":2,"text":"Collection Membership","anchor":"collection-membership","htmlText":"Collection Membership"},{"level":2,"text":"Strings","anchor":"strings","htmlText":"Strings"},{"level":2,"text":"Collection Elements","anchor":"collection-elements","htmlText":"Collection Elements"},{"level":3,"text":"Swift","anchor":"swift","htmlText":"Swift"},{"level":3,"text":"Objective-C","anchor":"objective-c","htmlText":"Objective-C"},{"level":2,"text":"Collection Count","anchor":"collection-count","htmlText":"Collection Count"},{"level":2,"text":"Notifications","anchor":"notifications","htmlText":"Notifications"},{"level":2,"text":"Result","anchor":"result","htmlText":"Result"},{"level":2,"text":"Matching a value to any of a group of matchers","anchor":"matching-a-value-to-any-of-a-group-of-matchers","htmlText":"Matching a value to any of a group of matchers"},{"level":2,"text":"Custom Validation","anchor":"custom-validation","htmlText":"Custom Validation"},{"level":1,"text":"Writing Your Own Matchers","anchor":"writing-your-own-matchers","htmlText":"Writing Your Own Matchers"},{"level":2,"text":"MatcherResult","anchor":"matcherresult","htmlText":"MatcherResult"},{"level":2,"text":"Lazy Evaluation","anchor":"lazy-evaluation","htmlText":"Lazy Evaluation"},{"level":2,"text":"Type Checking via Swift Generics","anchor":"type-checking-via-swift-generics","htmlText":"Type Checking via Swift Generics"},{"level":2,"text":"Customizing Failure Messages","anchor":"customizing-failure-messages","htmlText":"Customizing Failure Messages"},{"level":3,"text":"Basic Customization","anchor":"basic-customization","htmlText":"Basic Customization"},{"level":3,"text":"Full Customization","anchor":"full-customization","htmlText":"Full Customization"},{"level":2,"text":"Asynchronous Matchers","anchor":"asynchronous-matchers","htmlText":"Asynchronous Matchers"},{"level":2,"text":"Supporting Objective-C","anchor":"supporting-objective-c","htmlText":"Supporting Objective-C"},{"level":3,"text":"Properly Handling nil in Objective-C Matchers","anchor":"properly-handling-nil-in-objective-c-matchers","htmlText":"Properly Handling nil in Objective-C Matchers"},{"level":1,"text":"Installing Nimble","anchor":"installing-nimble","htmlText":"Installing Nimble"},{"level":2,"text":"Installing Nimble as a Submodule","anchor":"installing-nimble-as-a-submodule","htmlText":"Installing Nimble as a Submodule"},{"level":2,"text":"Installing Nimble via CocoaPods","anchor":"installing-nimble-via-cocoapods","htmlText":"Installing Nimble via CocoaPods"},{"level":2,"text":"Installing Nimble via Swift Package Manager","anchor":"installing-nimble-via-swift-package-manager","htmlText":"Installing Nimble via Swift Package Manager"},{"level":3,"text":"Xcode","anchor":"xcode","htmlText":"Xcode"},{"level":3,"text":"Package.Swift","anchor":"packageswift","htmlText":"Package.Swift"},{"level":2,"text":"Using Nimble without XCTest","anchor":"using-nimble-without-xctest","htmlText":"Using Nimble without XCTest"}],"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble"}},{"displayName":"LICENSE","repoName":"Nimble","refName":"main","path":"LICENSE","preferredFileType":"license","tabName":"Apache-2.0","richText":null,"loaded":false,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":null,"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble"}}],"overviewFilesProcessingTime":0}},"appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-7d7eb7c71814.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-708ec8ade250.js","githubDevUrl":null,"enabled_features":{"copilot_workspace":null,"code_nav_ui_events":false,"overview_shared_code_dropdown_button":true,"react_blob_overlay":false,"accessible_code_button":true,"github_models_repo_integration":false}}}}</script> <div data-target="react-partial.reactRoot"><style data-styled="true" data-styled-version="5.3.11">.iVEunk{margin-top:16px;margin-bottom:16px;}/*!sc*/ .jzuOtQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;}/*!sc*/ .bGojzy{margin-bottom:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;row-gap:16px;}/*!sc*/ .iNSVHo{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding-bottom:16px;padding-top:8px;}/*!sc*/ .bVgnfw{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:8px;}/*!sc*/ @media screen and (max-width:320px){.bVgnfw{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .CEgMp{position:relative;}/*!sc*/ @media screen and (max-width:380px){.CEgMp .ref-selector-button-text-container{max-width:80px;}}/*!sc*/ @media screen and (max-width:320px){.CEgMp{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}.CEgMp .overview-ref-selector{width:100%;}.CEgMp .overview-ref-selector > span{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;}.CEgMp .overview-ref-selector > span > span[data-component="text"]{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}}/*!sc*/ .gMOVLe[data-size="medium"]{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:0;}/*!sc*/ .gMOVLe[data-size="medium"] svg{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .gMOVLe[data-size="medium"] > span{width:inherit;}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .bZBlpz{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;}/*!sc*/ .lhTYNA{margin-right:4px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .ffLUq{font-size:14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}/*!sc*/ .bmcJak{min-width:0;}/*!sc*/ .fLXEGX{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1079px){.fLXEGX{display:none;}}/*!sc*/ .lmSMZJ[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));padding-left:4px;padding-right:4px;}/*!sc*/ .lmSMZJ[data-size="medium"] span[data-component="leadingVisual"]{margin-right:4px !important;}/*!sc*/ .dqfxud{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1080px){.dqfxud{display:none;}}/*!sc*/ @media screen and (max-width:543px){.dqfxud{display:none;}}/*!sc*/ .fGwBZA[data-size="medium"][data-no-visuals]{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));}/*!sc*/ .jxTzTd{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding-left:8px;gap:8px;}/*!sc*/ .gqqBXN{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;}/*!sc*/ @media screen and (max-width:543px){.gqqBXN{display:none;}}/*!sc*/ .dzXgxt{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (max-width:1011px){.dzXgxt{display:none;}}/*!sc*/ .iWFGlI{margin-left:8px;margin-right:8px;margin:0;}/*!sc*/ .vcvyP{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:160px;}/*!sc*/ .YUPas{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:1012px){.YUPas{display:none;}}/*!sc*/ .izFOf{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ @media screen and (min-width:544px){.izFOf{display:none;}}/*!sc*/ .cjVDqW{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;background-color:var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa));font-size:14px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;border:solid 1px;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;padding-left:16px;padding-right:8px;padding-top:8px;padding-bottom:8px;margin-bottom:16px;min-height:50px;}/*!sc*/ .vIPPs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:16px;}/*!sc*/ .fdROMU{width:100%;border-collapse:separate;border-spacing:0;border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;table-layout:fixed;overflow:unset;}/*!sc*/ .jGKpsv{height:0px;line-height:0px;}/*!sc*/ .jGKpsv tr{height:0px;font-size:0px;}/*!sc*/ .jdgHnn{padding:16px;color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;text-align:left;height:40px;}/*!sc*/ .jdgHnn th{padding-left:16px;background-color:var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa));}/*!sc*/ .bQivRW{width:100%;border-top-left-radius:6px;}/*!sc*/ @media screen and (min-width:544px){.bQivRW{display:none;}}/*!sc*/ .ldkMIO{width:40%;border-top-left-radius:6px;}/*!sc*/ @media screen and (max-width:543px){.ldkMIO{display:none;}}/*!sc*/ .jMbWeI{text-align:right;padding-right:16px;width:136px;border-top-right-radius:6px;}/*!sc*/ .gpqjiB{color:var(--fgColor-muted,var(--color-fg-muted,#656d76));font-size:12px;height:40px;}/*!sc*/ .dzCJzi{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;gap:8px;min-width:273px;padding:8px;}/*!sc*/ @media screen and (min-width:544px){.dzCJzi{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}/*!sc*/ .eNCcrz{text-align:center;vertical-align:center;height:40px;border-top:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));}/*!sc*/ .bHTcCe{border-top:1px solid var(--borderColor-default,var(--color-border-default));cursor:pointer;}/*!sc*/ .csrIcr{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;gap:16px;}/*!sc*/ .bUQNHB{border:1px solid;border-color:var(--borderColor-default,var(--color-border-default,#d0d7de));border-radius:6px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}/*!sc*/ @media screen and (max-width:543px){.bUQNHB{margin-left:-16px;margin-right:-16px;max-width:calc(100% + 32px);}}/*!sc*/ @media screen and (min-width:544px){.bUQNHB{max-width:100%;}}/*!sc*/ .jPdcfu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;border-bottom:1px solid;border-bottom-color:var(--borderColor-default,var(--color-border-default,#d0d7de));-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-right:8px;position:-webkit-sticky;position:sticky;top:0;background-color:var(--bgColor-default,var(--color-canvas-default,#ffffff));z-index:1;border-top-left-radius:6px;border-top-right-radius:6px;}/*!sc*/ .iphEWz{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;border-bottom:none;max-width:100%;padding-left:8px;padding-right:8px;}/*!sc*/ .hUCRAk{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .cwoBXV[data-size="medium"]{color:var(--fgColor-muted,var(--color-fg-subtle,#6e7781));padding-left:8px;padding-right:8px;}/*!sc*/ .QkQOb{padding:32px;overflow:auto;}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"iVEunk,jzuOtQ,bGojzy,iNSVHo,bVgnfw,CEgMp,gMOVLe,gUkoLg,bZBlpz,lhTYNA,ffLUq,bmcJak,fLXEGX,lmSMZJ,dqfxud,fGwBZA,jxTzTd,gqqBXN,dzXgxt,iWFGlI,vcvyP,YUPas,izFOf,cjVDqW,vIPPs,fdROMU,jGKpsv,jdgHnn,bQivRW,ldkMIO,jMbWeI,gpqjiB,dzCJzi,eNCcrz,bHTcCe,csrIcr,bUQNHB,jPdcfu,iphEWz,hUCRAk,cwoBXV,QkQOb,"}/*!sc*/ .brGdpi{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border-width:0;}/*!sc*/ data-styled.g5[id="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0"]{content:"brGdpi,"}/*!sc*/ .hWlpPn{position:relative;display:inline-block;}/*!sc*/ .hWlpPn::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .hWlpPn:hover::after,.hWlpPn:active::after,.hWlpPn:focus::after,.hWlpPn:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-no-delay:hover::after,.hWlpPn.tooltipped-no-delay:active::after,.hWlpPn.tooltipped-no-delay:focus::after,.hWlpPn.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .hWlpPn.tooltipped-multiline:hover::after,.hWlpPn.tooltipped-multiline:active::after,.hWlpPn.tooltipped-multiline:focus::after,.hWlpPn.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-se::after,.hWlpPn.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .hWlpPn.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-n::after,.hWlpPn.tooltipped-ne::after,.hWlpPn.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .hWlpPn.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .hWlpPn.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .hWlpPn.tooltipped-s::after,.hWlpPn.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .hWlpPn.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .hWlpPn.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-s::after,.hWlpPn.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .hWlpPn.tooltipped-multiline.tooltipped-w::after,.hWlpPn.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .hWlpPn.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .hWlpPn.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g16[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"hWlpPn,"}/*!sc*/ .liVpTx{display:inline-block;overflow:hidden;text-overflow:ellipsis;vertical-align:top;white-space:nowrap;max-width:125px;}/*!sc*/ data-styled.g18[id="Truncate__StyledTruncate-sc-23o1d2-0"]{content:"liVpTx,"}/*!sc*/ </style> <!-- --> <!-- --> <div class="Box-sc-g0xbh4-0 iVEunk"><div class="Box-sc-g0xbh4-0 jzuOtQ"><div class="Box-sc-g0xbh4-0 bGojzy"></div></div><div class="Box-sc-g0xbh4-0 iNSVHo"><div class="Box-sc-g0xbh4-0 bVgnfw"><div class="Box-sc-g0xbh4-0 CEgMp"><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" class="Box-sc-g0xbh4-0 gMOVLe prc-Button-ButtonBase-c50BI overview-ref-selector width-full" data-loading="false" data-size="medium" data-variant="default" aria-describedby="branch-picker-repos-header-ref-selector-loading-announcement" id="branch-picker-repos-header-ref-selector"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x"><div class="Box-sc-g0xbh4-0 bZBlpz"><div class="Box-sc-g0xbh4-0 lhTYNA"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></div><div class="Box-sc-g0xbh4-0 ffLUq ref-selector-button-text-container"><span class="Box-sc-g0xbh4-0 bmcJak prc-Text-Text-0ima0"> <!-- -->main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><button hidden="" data-hotkey-scope="read-only-cursor-text-area"></button></div><div class="Box-sc-g0xbh4-0 fLXEGX"><a style="--button-color:fg.muted" type="button" href="/younata/Nimble/branches" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rclab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Branches</span></span></a><a style="--button-color:fg.muted" type="button" href="/younata/Nimble/tags" class="Box-sc-g0xbh4-0 lmSMZJ prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rklab:-loading-announcement"><span data-component="buttonContent" class="Box-sc-g0xbh4-0 gUkoLg prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Tags</span></span></a></div><div class="Box-sc-g0xbh4-0 dqfxud"><a style="--button-color:fg.muted" type="button" aria-label="Go to Branches page" href="/younata/Nimble/branches" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Relab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></a><a style="--button-color:fg.muted" type="button" aria-label="Go to Tags page" href="/younata/Nimble/tags" class="Box-sc-g0xbh4-0 fGwBZA prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-describedby=":Rmlab:-loading-announcement"><svg aria-hidden="true" focusable="false" class="octicon octicon-tag" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path></svg></a></div></div><div class="Box-sc-g0xbh4-0 jxTzTd"><div class="Box-sc-g0xbh4-0 gqqBXN"><div class="Box-sc-g0xbh4-0 dzXgxt"><!--$--><div class="Box-sc-g0xbh4-0 iWFGlI"><span class="Box-sc-g0xbh4-0 vcvyP TextInput-wrapper prc-components-TextInputWrapper-i1ofR prc-components-TextInputBaseWrapper-ueK9q" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id=":R2j5ab:" aria-hidden="true"><svg aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellcheck="false" placeholder="Go to file" aria-describedby=":R2j5ab: :R2j5abH1:" data-component="input" class="prc-components-Input-Ic-y8" value=""/><span class="TextInput-icon" id=":R2j5abH1:" aria-hidden="true"></span></span></div><!--/$--></div><div class="Box-sc-g0xbh4-0 YUPas"><button type="button" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":Rr5ab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="text" class="prc-Button-Label-pTQ3x">Go to file</span></span></button></div><div class="react-directory-add-file-icon"></div><div class="react-directory-remove-file-icon"></div></div><button type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="primary" aria-describedby=":R55ab:-loading-announcement" id=":R55ab:"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-code hide-sm" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x">Code</span><span data-component="trailingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="Box-sc-g0xbh4-0 izFOf"><button data-component="IconButton" type="button" aria-label="Open more actions menu" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-c50BI prc-Button-IconButton-szpyj" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-describedby=":R75ab:-loading-announcement" id=":R75ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button></div></div></div><div data-testid="branch-info-bar" aria-live="polite" class="Box-sc-g0xbh4-0 cjVDqW"><div style="width:40%" class="Skeleton Skeleton--text"> </div><div style="width:30%" class="Skeleton Skeleton--text"> </div></div><div class="Box-sc-g0xbh4-0 vIPPs"><div data-hpc="true"><button hidden="" data-testid="focus-next-element-button" data-hotkey="j"></button><button hidden="" data-testid="focus-previous-element-button" data-hotkey="k"></button><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading" id="folders-and-files">Folders and files</h2><table aria-labelledby="folders-and-files" class="Box-sc-g0xbh4-0 fdROMU"><thead class="Box-sc-g0xbh4-0 jGKpsv"><tr class="Box-sc-g0xbh4-0 jdgHnn"><th colSpan="2" class="Box-sc-g0xbh4-0 bQivRW"><span class="text-bold">Name</span></th><th colSpan="1" class="Box-sc-g0xbh4-0 ldkMIO"><span class="text-bold">Name</span></th><th class="hide-sm"><div title="Last commit message" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit message</span></div></th><th colSpan="1" class="Box-sc-g0xbh4-0 jMbWeI"><div title="Last commit date" class="Truncate__StyledTruncate-sc-23o1d2-0 liVpTx width-fit"><span class="text-bold">Last commit date</span></div></th></tr></thead><tbody><tr class="Box-sc-g0xbh4-0 gpqjiB"><td colSpan="3" class="bgColor-muted p-1 rounded-top-2"><div class="Box-sc-g0xbh4-0 dzCJzi"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone--vW4Cq prc-Heading-Heading-6CmGO" data-testid="screen-reader-heading">History</h2><a href="/younata/Nimble/commits/main/" class="prc-Button-ButtonBase-c50BI d-none d-lg-flex LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":Raqj8pab:-loading-announcement"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-pTQ3x"><span class="fgColor-default">1,914 Commits</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><span role="tooltip" aria-label="1,914 Commits" id="history-icon-button-tooltip" class="Tooltip__TooltipBase-sc-17tf59c-0 hWlpPn tooltipped-n"><a href="/younata/Nimble/commits/main/" class="prc-Button-ButtonBase-c50BI LinkButton-module__code-view-link-button--xvCGA flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby=":R1iqj8pab:-loading-announcement history-icon-button-tooltip"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-HKbr-"><span data-component="leadingVisual" class="prc-Button-Visual-2epfX prc-Button-VisualWrap-Db-eB"><svg aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a></span></div></div></div></div></td></tr><tr class="react-directory-row undefined" id="folder-row-0"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".github" aria-label=".github, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/.github">.github</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".github" aria-label=".github, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/.github">.github</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-1"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Nimble.xcodeproj" aria-label="Nimble.xcodeproj, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Nimble.xcodeproj">Nimble.xcodeproj</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Nimble.xcodeproj" aria-label="Nimble.xcodeproj, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Nimble.xcodeproj">Nimble.xcodeproj</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-2"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Sources" aria-label="Sources, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Sources">Sources</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Sources" aria-label="Sources, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Sources">Sources</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-3"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Tests" aria-label="Tests, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Tests">Tests</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Tests" aria-label="Tests, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/Tests">Tests</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-4"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="docs" aria-label="docs, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/docs">docs</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="docs" aria-label="docs, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/docs">docs</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-5"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="script" aria-label="script, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/script">script</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file-directory-fill icon-directory" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1A1.75 1.75 0 0 0 0 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0 0 16 13.25v-8.5A1.75 1.75 0 0 0 14.25 3H7.5a.25.25 0 0 1-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="script" aria-label="script, (Directory)" class="Link--primary" href="/younata/Nimble/tree/main/script">script</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-6"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/younata/Nimble/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".gitignore" aria-label=".gitignore, (File)" class="Link--primary" href="/younata/Nimble/blob/main/.gitignore">.gitignore</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-7"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".swiftlint.yml" aria-label=".swiftlint.yml, (File)" class="Link--primary" href="/younata/Nimble/blob/main/.swiftlint.yml">.swiftlint.yml</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title=".swiftlint.yml" aria-label=".swiftlint.yml, (File)" class="Link--primary" href="/younata/Nimble/blob/main/.swiftlint.yml">.swiftlint.yml</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-8"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CONTRIBUTING.md" aria-label="CONTRIBUTING.md, (File)" class="Link--primary" href="/younata/Nimble/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="CONTRIBUTING.md" aria-label="CONTRIBUTING.md, (File)" class="Link--primary" href="/younata/Nimble/blob/main/CONTRIBUTING.md">CONTRIBUTING.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row undefined" id="folder-row-9"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cartfile.resolved" aria-label="Cartfile.resolved, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Cartfile.resolved">Cartfile.resolved</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Cartfile.resolved" aria-label="Cartfile.resolved, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Cartfile.resolved">Cartfile.resolved</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-10"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Dockerfile.test" aria-label="Dockerfile.test, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Dockerfile.test">Dockerfile.test</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Dockerfile.test" aria-label="Dockerfile.test, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Dockerfile.test">Dockerfile.test</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-11"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Gemfile" aria-label="Gemfile, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Gemfile">Gemfile</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Gemfile" aria-label="Gemfile, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Gemfile">Gemfile</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-12"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Gemfile.lock" aria-label="Gemfile.lock, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Gemfile.lock">Gemfile.lock</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Gemfile.lock" aria-label="Gemfile.lock, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Gemfile.lock">Gemfile.lock</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-13"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE" aria-label="LICENSE, (File)" class="Link--primary" href="/younata/Nimble/blob/main/LICENSE">LICENSE</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="LICENSE" aria-label="LICENSE, (File)" class="Link--primary" href="/younata/Nimble/blob/main/LICENSE">LICENSE</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-14"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Nimble.podspec" aria-label="Nimble.podspec, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Nimble.podspec">Nimble.podspec</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Nimble.podspec" aria-label="Nimble.podspec, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Nimble.podspec">Nimble.podspec</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-15"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Package.resolved" aria-label="Package.resolved, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Package.resolved">Package.resolved</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Package.resolved" aria-label="Package.resolved, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Package.resolved">Package.resolved</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-16"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Package.swift" aria-label="Package.swift, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Package.swift">Package.swift</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="Package.swift" aria-label="Package.swift, (File)" class="Link--primary" href="/younata/Nimble/blob/main/Package.swift">Package.swift</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-17"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/younata/Nimble/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="README.md" aria-label="README.md, (File)" class="Link--primary" href="/younata/Nimble/blob/main/README.md">README.md</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="react-directory-row truncate-for-mobile" id="folder-row-18"><td class="react-directory-row-name-cell-small-screen" colSpan="2"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="test" aria-label="test, (File)" class="Link--primary" href="/younata/Nimble/blob/main/test">test</a></div></div></div></div></td><td class="react-directory-row-name-cell-large-screen" colSpan="1"><div class="react-directory-filename-column"><svg aria-hidden="true" focusable="false" class="octicon octicon-file color-fg-muted" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V6h-2.75A1.75 1.75 0 0 1 9 4.25V1.5Zm6.75.062V4.25c0 .138.112.25.25.25h2.688l-.011-.013-2.914-2.914-.013-.011Z"></path></svg><div class="overflow-hidden"><div class="react-directory-filename-cell"><div class="react-directory-truncate"><a title="test" aria-label="test, (File)" class="Link--primary" href="/younata/Nimble/blob/main/test">test</a></div></div></div></div></td><td class="react-directory-row-commit-cell"><div class="Skeleton Skeleton--text"> </div></td><td><div class="Skeleton Skeleton--text"> </div></td></tr><tr class="Box-sc-g0xbh4-0 eNCcrz show-for-mobile" data-testid="view-all-files-row"><td colSpan="3" class="Box-sc-g0xbh4-0 bHTcCe"><div><button class="prc-Link-Link-85e08">View all files</button></div></td></tr></tbody></table></div><div class="Box-sc-g0xbh4-0 csrIcr"><div class="Box-sc-g0xbh4-0 bUQNHB"><div itemscope="" itemType="https://schema.org/abstract" class="Box-sc-g0xbh4-0 jPdcfu"><h2 class="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0 brGdpi">Repository files navigation</h2><nav class="Box-sc-g0xbh4-0 iphEWz prc-components-UnderlineWrapper-oOh5J" aria-label="Repository files"><ul class="prc-components-UnderlineItemList-b23Hf" role="list"><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#" aria-current="page"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-book" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path></svg></span><span data-component="text" data-content="README">README</span></a></li><li class="Box-sc-g0xbh4-0 hUCRAk"><a class="prc-components-UnderlineItem-lJsg-" href="#"><span data-component="icon"><svg aria-hidden="true" focusable="false" class="octicon octicon-law" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path></svg></span><span data-component="text" data-content="Apache-2.0 license">Apache-2.0 license</span></a></li></ul></nav><button style="--button-color:fg.subtle" type="button" aria-label="Outline" aria-haspopup="true" aria-expanded="false" tabindex="0" class="Box-sc-g0xbh4-0 cwoBXV prc-Button-ButtonBase-c50BI" data-loading="false" data-size="medium" data-variant="invisible" aria-describedby=":Rr9ab:-loading-announcement" id=":Rr9ab:"><svg aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button></div><div class="Box-sc-g0xbh4-0 QkQOb js-snippet-clipboard-copy-unpositioned undefined" data-hpc="true"><article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Nimble</h1><a id="user-content-nimble" class="anchor" aria-label="Permalink: Nimble" href="#nimble"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://github.com/Quick/Nimble/actions/workflows/ci-xcode.yml"><img src="https://github.com/Quick/Nimble/actions/workflows/ci-xcode.yml/badge.svg" alt="Build Status" style="max-width: 100%;"></a> <a href="https://cocoapods.org/pods/Nimble" rel="nofollow"><img src="https://camo.githubusercontent.com/017de8a282248d27c83840aac0d4dde210b0be9e04561d35101c2f6798c8ba7d/68747470733a2f2f696d672e736869656c64732e696f2f636f636f61706f64732f762f4e696d626c652e737667" alt="CocoaPods" data-canonical-src="https://img.shields.io/cocoapods/v/Nimble.svg" style="max-width: 100%;"></a> <a href="https://github.com/Carthage/Carthage"><img src="https://camo.githubusercontent.com/5cb89494518efc818a124fd801726287be9482423d1a161a6dec2066aa0f30db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f43617274686167652d636f6d70617469626c652d3442433531442e7376673f7374796c653d666c6174" alt="Carthage Compatible" data-canonical-src="https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat" style="max-width: 100%;"></a> <a href="https://cocoapods.org/pods/Nimble" rel="nofollow"><img src="https://camo.githubusercontent.com/915a4c2f0baf0e08e00091ebbb1b1f5c625a07d5e9a8715868d3d8ecd05e3f4f/68747470733a2f2f696d672e736869656c64732e696f2f636f636f61706f64732f702f4e696d626c652e737667" alt="Platforms" data-canonical-src="https://img.shields.io/cocoapods/p/Nimble.svg" style="max-width: 100%;"></a></p> <p dir="auto">Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by <a href="https://github.com/pivotal/cedar">Cedar</a>.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(1 + 1).to(equal(2)) expect(1.2).to(beCloseTo(1.1, within: 0.1)) expect(3) > 2 expect("seahorse").to(contain("sea")) expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi")) expect(ocean.isClean).toEventually(beTruthy())"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1.2</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beCloseTo</span><span class="pl-kos">(</span><span class="pl-c1">1.1</span><span class="pl-kos">,</span> within<span class="pl-kos">:</span> <span class="pl-c1">0.1</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span> <span class="pl-c1">></span> <span class="pl-c1">2</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">seahorse</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">sea</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-s">"</span><span class="pl-s">Atlantic</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">Pacific</span><span class="pl-s">"</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Mississippi</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">.</span>isClean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">beTruthy</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">How to Use Nimble</h1><a id="user-content-how-to-use-nimble" class="anchor" aria-label="Permalink: How to Use Nimble" href="#how-to-use-nimble"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Table of Contents</strong> <em>generated with <a href="https://github.com/thlorenz/doctoc">DocToc</a></em></p> <ul dir="auto"> <li><a href="#some-background-expressing-outcomes-using-assertions-in-xctest">Some Background: Expressing Outcomes Using Assertions in XCTest</a></li> <li><a href="#nimble-expectations-using-expectto">Nimble: Expectations Using <code>expect(...).to</code></a> <ul dir="auto"> <li><a href="#custom-failure-messages">Custom Failure Messages</a></li> <li><a href="#type-safety">Type Safety</a></li> <li><a href="#operator-overloads">Operator Overloads</a></li> <li><a href="#lazily-computed-values">Lazily Computed Values</a></li> <li><a href="#c-primitives">C Primitives</a></li> <li><a href="#asyncawait-support">Async/Await Support</a> <ul dir="auto"> <li><a href="#async-matchers">Async Matchers</a></li> </ul> </li> <li><a href="#polling-expectations">Polling Expectations</a> <ul dir="auto"> <li><a href="#using-polling-expectations-in-async-tests">Using Polling Expectations in Async Tests</a></li> <li><a href="#verifying-a-matcher-will-never-or-always-match">Verifying a Matcher will Never or Always Match</a></li> <li><a href="#waiting-for-a-callback-to-be-called">Waiting for a Callback to be Called</a></li> <li><a href="#changing-the-timeout-and-polling-intervals">Changing the Timeout and Polling Intervals</a></li> <li><a href="#changing-default-timeout-and-poll-intervals">Changing default Timeout and Poll Intervals</a> <ul dir="auto"> <li><a href="#quick">Quick</a></li> <li><a href="#xctest">XCTest</a></li> </ul> </li> </ul> </li> <li><a href="#objective-c-support">Objective-C Support</a></li> <li><a href="#disabling-objective-c-shorthand">Disabling Objective-C Shorthand</a></li> </ul> </li> <li><a href="#using-require-to-demand-that-a-matcher-pass-before-continuing">Using <code>require</code> to demand that a matcher pass before continuing</a> <ul dir="auto"> <li><a href="#polling-with-require">Polling with <code>require</code>.</a></li> <li><a href="#using-require-with-async-expressions-and-async-matchers">Using <code>require</code> with Async expressions and Async matchers</a></li> <li><a href="#using-unwrap-to-replace-requiretonotbenil">Using <code>unwrap</code> to replace <code>require(...).toNot(beNil())</code></a></li> <li><a href="#throwing-a-custom-error-from-require">Throwing a Custom Error from Require</a></li> </ul> </li> <li><a href="#built-in-matcher-functions">Built-in Matcher Functions</a> <ul dir="auto"> <li><a href="#type-checking">Type Checking</a></li> <li><a href="#equivalence">Equivalence</a></li> <li><a href="#identity">Identity</a></li> <li><a href="#comparisons">Comparisons</a></li> <li><a href="#typesclasses">Types/Classes</a></li> <li><a href="#truthiness">Truthiness</a></li> <li><a href="#swift-assertions">Swift Assertions</a></li> <li><a href="#swift-error-handling">Swift Error Handling</a></li> <li><a href="#exceptions">Exceptions</a></li> <li><a href="#collection-membership">Collection Membership</a></li> <li><a href="#strings">Strings</a></li> <li><a href="#collection-elements">Collection Elements</a> <ul dir="auto"> <li><a href="#swift">Swift</a></li> <li><a href="#objective-c">Objective-C</a></li> </ul> </li> <li><a href="#collection-count">Collection Count</a></li> <li><a href="#notifications">Notifications</a></li> <li><a href="#result">Result</a></li> <li><a href="#matching-a-value-to-any-of-a-group-of-matchers">Matching a value to any of a group of matchers</a></li> <li><a href="#custom-validation">Custom Validation</a></li> </ul> </li> <li><a href="#writing-your-own-matchers">Writing Your Own Matchers</a> <ul dir="auto"> <li><a href="#matcherresult">MatcherResult</a></li> <li><a href="#lazy-evaluation">Lazy Evaluation</a></li> <li><a href="#type-checking-via-swift-generics">Type Checking via Swift Generics</a></li> <li><a href="#customizing-failure-messages">Customizing Failure Messages</a> <ul dir="auto"> <li><a href="#basic-customization">Basic Customization</a></li> <li><a href="#full-customization">Full Customization</a></li> </ul> </li> <li><a href="#asynchronous-matchers">Asynchronous Matchers</a></li> <li><a href="#supporting-objective-c">Supporting Objective-C</a> <ul dir="auto"> <li><a href="#properly-handling-nil-in-objective-c-matchers">Properly Handling <code>nil</code> in Objective-C Matchers</a></li> </ul> </li> </ul> </li> <li><a href="#installing-nimble">Installing Nimble</a> <ul dir="auto"> <li><a href="#installing-nimble-as-a-submodule">Installing Nimble as a Submodule</a></li> <li><a href="#installing-nimble-via-cocoapods">Installing Nimble via CocoaPods</a></li> <li><a href="#installing-nimble-via-swift-package-manager">Installing Nimble via Swift Package Manager</a> <ul dir="auto"> <li><a href="#xcode">Xcode</a></li> <li><a href="#packageswift">Package.Swift</a></li> </ul> </li> <li><a href="#using-nimble-without-xctest">Using Nimble without XCTest</a></li> </ul> </li> </ul> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Some Background: Expressing Outcomes Using Assertions in XCTest</h1><a id="user-content-some-background-expressing-outcomes-using-assertions-in-xctest" class="anchor" aria-label="Permalink: Some Background: Expressing Outcomes Using Assertions in XCTest" href="#some-background-expressing-outcomes-using-assertions-in-xctest"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Apple's Xcode includes the XCTest framework, which provides assertion macros to test whether code behaves properly. For example, to assert that <code>1 + 1 = 2</code>, XCTest has you write:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift XCTAssertEqual(1 + 1, 2, "expected one plus one to equal two")"><pre>// Swift <span class="pl-en">XCTAssertEqual</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">expected one plus one to equal two</span><span class="pl-s">"</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Or, in Objective-C:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C XCTAssertEqual(1 + 1, 2, @"expected one plus one to equal two");"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">XCTAssertEqual</span>(<span class="pl-c1">1</span> + <span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-s"><span class="pl-pds">@"</span>expected one plus one to equal two<span class="pl-pds">"</span></span>);</pre></div> <p dir="auto">XCTest assertions have a couple of drawbacks:</p> <ol dir="auto"> <li><strong>Not enough macros.</strong> There's no easy way to assert that a string contains a particular substring, or that a number is less than or equal to another.</li> <li><strong>It's hard to write asynchronous tests.</strong> XCTest forces you to write a lot of boilerplate code.</li> </ol> <p dir="auto">Nimble addresses these concerns.</p> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Nimble: Expectations Using <code>expect(...).to</code></h1><a id="user-content-nimble-expectations-using-expectto" class="anchor" aria-label="Permalink: Nimble: Expectations Using expect(...).to" href="#nimble-expectations-using-expectto"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble allows you to express expectations using a natural, easily understood language:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift import Nimble expect(seagull.squawk).to(equal("Squee!"))"><pre>// Swift <span class="pl-k">import</span> Nimble <span class="pl-en">expect</span><span class="pl-kos">(</span>seagull<span class="pl-kos">.</span>squawk<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Squee!</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C @import Nimble; expect(seagull.squawk).to(equal(@"Squee!"));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> @import Nimble; <span class="pl-en">expect</span>(seagull.squawk).to(equal(<span class="pl-s"><span class="pl-pds">@"</span>Squee!<span class="pl-pds">"</span></span>));</pre></div> <blockquote> <p dir="auto">The <code>expect</code> function autocompletes to include <code>file:</code> and <code>line:</code>, but these parameters are optional. Use the default values to have Xcode highlight the correct line when an expectation is not met.</p> </blockquote> <p dir="auto">To perform the opposite expectation--to assert something is <em>not</em> equal--use <code>toNot</code> or <code>notTo</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift import Nimble expect(seagull.squawk).toNot(equal("Oh, hello there!")) expect(seagull.squawk).notTo(equal("Oh, hello there!"))"><pre>// Swift <span class="pl-k">import</span> Nimble <span class="pl-en">expect</span><span class="pl-kos">(</span>seagull<span class="pl-kos">.</span>squawk<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Oh, hello there!</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>seagull<span class="pl-kos">.</span>squawk<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">notTo</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Oh, hello there!</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C @import Nimble; expect(seagull.squawk).toNot(equal(@"Oh, hello there!")); expect(seagull.squawk).notTo(equal(@"Oh, hello there!"));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> @import Nimble; <span class="pl-en">expect</span>(seagull.squawk).toNot(equal(<span class="pl-s"><span class="pl-pds">@"</span>Oh, hello there!<span class="pl-pds">"</span></span>)); <span class="pl-en">expect</span>(seagull.squawk).notTo(equal(<span class="pl-s"><span class="pl-pds">@"</span>Oh, hello there!<span class="pl-pds">"</span></span>));</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Custom Failure Messages</h2><a id="user-content-custom-failure-messages" class="anchor" aria-label="Permalink: Custom Failure Messages" href="#custom-failure-messages"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Would you like to add more information to the test's failure messages? Use the <code>description</code> optional argument to add your own text:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(1 + 1).to(equal(3)) // failed - expected to equal <3>, got <2> expect(1 + 1).to(equal(3), description: "Make sure libKindergartenMath is loaded") // failed - Make sure libKindergartenMath is loaded // expected to equal <3>, got <2>"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // failed - expected to equal <3>, got <2> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">,</span> description<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">Make sure libKindergartenMath is loaded</span><span class="pl-s">"</span><span class="pl-kos">)</span> // failed - Make sure libKindergartenMath is loaded // expected to equal <3>, got <2></pre></div> <p dir="auto">Or the *WithDescription version in Objective-C:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C @import Nimble; expect(@(1+1)).to(equal(@3)); // failed - expected to equal <3.0000>, got <2.0000> expect(@(1+1)).toWithDescription(equal(@3), @"Make sure libKindergartenMath is loaded"); // failed - Make sure libKindergartenMath is loaded // expected to equal <3.0000>, got <2.0000>"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> @import Nimble; <span class="pl-en">expect</span>(@(<span class="pl-c1">1</span>+<span class="pl-c1">1</span>)).to(equal(@<span class="pl-c1">3</span>)); <span class="pl-c"><span class="pl-c">//</span> failed - expected to equal <3.0000>, got <2.0000></span> <span class="pl-en">expect</span>(@(<span class="pl-c1">1</span>+<span class="pl-c1">1</span>)).toWithDescription(equal(@<span class="pl-c1">3</span>), @"Make sure libKindergartenMath is loaded"); <span class="pl-c"><span class="pl-c">//</span> failed - Make sure libKindergartenMath is loaded</span> <span class="pl-c"><span class="pl-c">//</span> expected to equal <3.0000>, got <2.0000></span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Type Safety</h2><a id="user-content-type-safety" class="anchor" aria-label="Permalink: Type Safety" href="#type-safety"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble makes sure you don't compare two types that don't match:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Does not compile: expect(1 + 1).to(equal("Squee!"))"><pre>// Swift // Does not compile: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-c1">+</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Squee!</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <blockquote> <p dir="auto">Nimble uses generics--only available in Swift--to ensure type correctness. That means type checking is not available when using Nimble in Objective-C. 😭</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Operator Overloads</h2><a id="user-content-operator-overloads" class="anchor" aria-label="Permalink: Operator Overloads" href="#operator-overloads"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Tired of so much typing? With Nimble, you can use overloaded operators like <code>==</code> for equivalence, or <code>></code> for comparisons:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if squawk does not equal "Hi!": expect(seagull.squawk) != "Hi!" // Passes if 10 is greater than 2: expect(10) > 2"><pre>// Swift // Passes if squawk does not equal "Hi!": <span class="pl-en">expect</span><span class="pl-kos">(</span>seagull<span class="pl-kos">.</span>squawk<span class="pl-kos">)</span> <span class="pl-c1">!=</span> <span class="pl-s">"</span><span class="pl-s">Hi!</span><span class="pl-s">"</span> // Passes if 10 is greater than 2: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">10</span><span class="pl-kos">)</span> <span class="pl-c1">></span> <span class="pl-c1">2</span></pre></div> <blockquote> <p dir="auto">Operator overloads are only available in Swift, so you won't be able to use this syntax in Objective-C. 💔</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Lazily Computed Values</h2><a id="user-content-lazily-computed-values" class="anchor" aria-label="Permalink: Lazily Computed Values" href="#lazily-computed-values"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The <code>expect</code> function doesn't evaluate the value it's given until it's time to match. So Nimble can test whether an expression raises an exception once evaluated:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Note: Swift currently doesn't have exceptions. // Only Objective-C code can raise exceptions // that Nimble will catch. // (see https://github.com/Quick/Nimble/issues/220#issuecomment-172667064) let exception = NSException( name: NSInternalInconsistencyException, reason: "Not enough fish in the sea.", userInfo: ["something": "is fishy"]) expect { exception.raise() }.to(raiseException()) // Also, you can customize raiseException to be more specific expect { exception.raise() }.to(raiseException(named: NSInternalInconsistencyException)) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea")) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea", userInfo: ["something": "is fishy"]))"><pre>// Swift // Note: Swift currently doesn't have exceptions. // Only Objective-C code can raise exceptions // that Nimble will catch. // (see https://github.com/Quick/Nimble/issues/220#issuecomment-172667064) <span class="pl-k">let</span> <span class="pl-s1">exception</span> <span class="pl-c1">=</span> <span class="pl-en">NSException</span><span class="pl-kos">(</span> name<span class="pl-kos">:</span> NSInternalInconsistencyException<span class="pl-kos">,</span> reason<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">Not enough fish in the sea.</span><span class="pl-s">"</span><span class="pl-kos">,</span> userInfo<span class="pl-kos">:</span> <span class="pl-kos">[</span><span class="pl-s">"</span><span class="pl-s">something</span><span class="pl-s">"</span><span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">is fishy</span><span class="pl-s">"</span><span class="pl-kos">]</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> exception<span class="pl-kos">.</span><span class="pl-en">raise</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Also, you can customize raiseException to be more specific <span class="pl-en">expect</span> <span class="pl-kos">{</span> exception<span class="pl-kos">.</span><span class="pl-en">raise</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span>named<span class="pl-kos">:</span> NSInternalInconsistencyException<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> exception<span class="pl-kos">.</span><span class="pl-en">raise</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span> named<span class="pl-kos">:</span> NSInternalInconsistencyException<span class="pl-kos">,</span> reason<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">Not enough fish in the sea</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> exception<span class="pl-kos">.</span><span class="pl-en">raise</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span> named<span class="pl-kos">:</span> NSInternalInconsistencyException<span class="pl-kos">,</span> reason<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">Not enough fish in the sea</span><span class="pl-s">"</span><span class="pl-kos">,</span> userInfo<span class="pl-kos">:</span> <span class="pl-kos">[</span><span class="pl-s">"</span><span class="pl-s">something</span><span class="pl-s">"</span><span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">is fishy</span><span class="pl-s">"</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Objective-C works the same way, but you must use the <code>expectAction</code> macro when making an expectation on an expression that has no return value:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Not enough fish in the sea." userInfo:nil]; expectAction(^{ [exception raise]; }).to(raiseException()); // Use the property-block syntax to be more specific. expectAction(^{ [exception raise]; }).to(raiseException().named(NSInternalInconsistencyException)); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea")); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea"). userInfo(@{@"something": @"is fishy"})); // You can also pass a block for custom matching of the raised exception expectAction(exception.raise()).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(NSInternalInconsistencyException)); }));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c1">NSException</span> *<span class="pl-c1">exception</span> = [<span class="pl-c1">NSException</span> <span class="pl-c1">exceptionWithName:</span><span class="pl-c1">NSInternalInconsistencyException</span> <span class="pl-c1">reason:</span><span class="pl-s"><span class="pl-pds">@"</span>Not enough fish in the sea.<span class="pl-pds">"</span></span> <span class="pl-c1">userInfo:</span><span class="pl-c1">nil</span>]; <span class="pl-en">expectAction</span>(^{ [<span class="pl-c1">exception</span> <span class="pl-c1">raise</span>]; }).to(raiseException()); <span class="pl-c"><span class="pl-c">//</span> Use the property-block syntax to be more specific.</span> <span class="pl-en">expectAction</span>(^{ [<span class="pl-c1">exception</span> <span class="pl-c1">raise</span>]; }).to(raiseException().named(<span class="pl-c1">NSInternalInconsistencyException</span>)); <span class="pl-en">expectAction</span>(^{ [<span class="pl-c1">exception</span> <span class="pl-c1">raise</span>]; }).to(raiseException(). named(<span class="pl-c1">NSInternalInconsistencyException</span>). reason(<span class="pl-s"><span class="pl-pds">"</span>Not enough fish in the sea<span class="pl-pds">"</span></span>)); <span class="pl-en">expectAction</span>(^{ [<span class="pl-c1">exception</span> <span class="pl-c1">raise</span>]; }).to(raiseException(). named(<span class="pl-c1">NSInternalInconsistencyException</span>). reason(<span class="pl-s"><span class="pl-pds">"</span>Not enough fish in the sea<span class="pl-pds">"</span></span>). userInfo(@{<span class="pl-s"><span class="pl-pds">@"</span>something<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">@"</span>is fishy<span class="pl-pds">"</span></span>})); <span class="pl-c"><span class="pl-c">//</span> You can also pass a block for custom matching of the raised exception</span> <span class="pl-en">expectAction</span>(<span class="pl-c1">exception</span>.raise()).to(raiseException().satisfyingBlock(^(<span class="pl-c1">NSException</span> *<span class="pl-c1">exception</span>) { <span class="pl-c1">expect</span>(<span class="pl-c1">exception</span>.<span class="pl-smi">name</span>).<span class="pl-c1">to</span>(<span class="pl-c1">beginWith</span>(<span class="pl-c1">NSInternalInconsistencyException</span>)); }));</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">C Primitives</h2><a id="user-content-c-primitives" class="anchor" aria-label="Permalink: C Primitives" href="#c-primitives"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Some testing frameworks make it hard to test primitive C values. In Nimble, it just works:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift let actual: CInt = 1 let expectedValue: CInt = 1 expect(actual).to(equal(expectedValue))"><pre>// Swift <span class="pl-k">let</span> <span class="pl-s1">actual</span><span class="pl-kos">:</span> <span class="pl-smi">CInt</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span> <span class="pl-k">let</span> <span class="pl-s1">expectedValue</span><span class="pl-kos">:</span> <span class="pl-smi">CInt</span> <span class="pl-c1">=</span> <span class="pl-c1">1</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span>expectedValue<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">In fact, Nimble uses type inference, so you can write the above without explicitly specifying both types:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(1 as CInt).to(equal(1))"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-k">as</span> <span class="pl-smi">CInt</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <blockquote> <p dir="auto">In Objective-C, Nimble only supports Objective-C objects. To make expectations on primitive C values, wrap then in an object literal:</p> </blockquote> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="expect(@(1 + 1)).to(equal(@2));"><pre><span class="pl-en">expect</span>(@(<span class="pl-c1">1</span> + <span class="pl-c1">1</span>)).to(equal(@<span class="pl-c1">2</span>));</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Async/Await Support</h2><a id="user-content-asyncawait-support" class="anchor" aria-label="Permalink: Async/Await Support" href="#asyncawait-support"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble makes it easy to await for an async function to complete. Simply pass the async function in to <code>expect</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift await expect { await aFunctionReturning1() }.to(equal(1))"><pre>// Swift <span class="pl-k">await</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-k">await</span> <span class="pl-en">aFunctionReturning1</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">The async function is awaited on first, before passing it to the matcher. This enables the matcher to run synchronous code like before, without caring about whether the value it's processing was abtained async or not.</p> <p dir="auto">Async support is Swift-only, and it requires that you execute the test in an async context. For XCTest, this is as simple as marking your test function with <code>async</code>. If you use Quick, all tests in Quick 6 are executed in an async context. In Quick 7 and later, only tests that are in an <code>AsyncSpec</code> subclass will be executed in an async context.</p> <p dir="auto">To avoid a compiler errors when using synchronous <code>expect</code> in asynchronous contexts, <code>expect</code> with async expressions does not support autoclosures. However, the <code>expecta</code> (expect async) function is provided as an alternative, which does support autoclosures.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift await expecta(await aFunctionReturning1()).to(equal(1)))"><pre>// Swift <span class="pl-k">await</span> <span class="pl-en">expecta</span><span class="pl-kos">(</span><span class="pl-k">await</span> <span class="pl-en">aFunctionReturning1</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Similarly, if you're ever in a situation where you want to force the compiler to produce a <code>SyncExpectation</code>, you can use the <code>expects</code> (expect sync) function to produce a <code>SyncExpectation</code>. Like so:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expects(someNonAsyncFunction()).to(equal(1))) expects(await someAsyncFunction()).to(equal(1)) // Compiler error: 'async' call in an autoclosure that does not support concurrency"><pre>// Swift <span class="pl-en">expects</span><span class="pl-kos">(</span><span class="pl-en">someNonAsyncFunction</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expects</span><span class="pl-kos">(</span><span class="pl-k">await</span> <span class="pl-en">someAsyncFunction</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Compiler error: 'async' call in an autoclosure that does not support concurrency</pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Async Matchers</h3><a id="user-content-async-matchers" class="anchor" aria-label="Permalink: Async Matchers" href="#async-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In addition to asserting on async functions prior to passing them to a synchronous matcher, you can also write matchers that directly take in an async value. These are called <code>AsyncMatcher</code>s. This is most obviously useful when directly asserting against an actor. In addition to writing your own async matchers, Nimble currently ships with async versions of the following matchers:</p> <ul dir="auto"> <li><code>allPass</code></li> <li><code>containElementSatisfying</code></li> <li><code>satisfyAllOf</code> and the <code>&&</code> operator overload accept both <code>AsyncMatcher</code> and synchronous <code>Matcher</code>s.</li> <li><code>satisfyAnyOf</code> and the <code>||</code> operator overload accept both <code>AsyncMatcher</code> and synchronous <code>Matcher</code>s.</li> </ul> <p dir="auto">Note: Async/Await support is different than the <code>toEventually</code>/<code>toEventuallyNot</code> feature described below.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Polling Expectations</h2><a id="user-content-polling-expectations" class="anchor" aria-label="Permalink: Polling Expectations" href="#polling-expectations"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In Nimble, it's easy to make expectations on values that are updated asynchronously. Just use <code>toEventually</code> or <code>toEventuallyNot</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift DispatchQueue.main.async { ocean.add("dolphins") ocean.add("whales") } expect(ocean).toEventually(contain("dolphins", "whales"))"><pre>// Swift <span class="pl-smi">DispatchQueue</span><span class="pl-kos">.</span>main<span class="pl-kos">.</span><span class="pl-en"><span class="pl-k">async</span></span> <span class="pl-kos">{</span> ocean<span class="pl-kos">.</span><span class="pl-en">add</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphins</span><span class="pl-s">"</span><span class="pl-kos">)</span> ocean<span class="pl-kos">.</span><span class="pl-en">add</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">whales</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphins</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">whales</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C dispatch_async(dispatch_get_main_queue(), ^{ [ocean add:@"dolphins"]; [ocean add:@"whales"]; }); expect(ocean).toEventually(contain(@"dolphins", @"whales"));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">dispatch_async</span>(dispatch_get_main_queue(), ^{ [ocean <span class="pl-c1">add:</span><span class="pl-s"><span class="pl-pds">@"</span>dolphins<span class="pl-pds">"</span></span>]; [ocean <span class="pl-c1">add:</span><span class="pl-s"><span class="pl-pds">@"</span>whales<span class="pl-pds">"</span></span>]; }); <span class="pl-en">expect</span>(ocean).toEventually(contain(<span class="pl-s"><span class="pl-pds">@"</span>dolphins<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">@"</span>whales<span class="pl-pds">"</span></span>));</pre></div> <p dir="auto">Note: toEventually triggers its polls on the main thread. Blocking the main thread will cause Nimble to stop the run loop. This can cause test pollution for whatever incomplete code that was running on the main thread. Blocking the main thread can be caused by blocking IO, calls to sleep(), deadlocks, and synchronous IPC.</p> <p dir="auto">In the above example, <code>ocean</code> is constantly re-evaluated. If it ever contains dolphins and whales, the expectation passes. If <code>ocean</code> still doesn't contain them, even after being continuously re-evaluated for one whole second, the expectation fails.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Using Polling Expectations in Async Tests</h3><a id="user-content-using-polling-expectations-in-async-tests" class="anchor" aria-label="Permalink: Using Polling Expectations in Async Tests" href="#using-polling-expectations-in-async-tests"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">You can easily use <code>toEventually</code> or <code>toEventuallyNot</code> in async contexts as well. You only need to add an <code>await</code> statement to the beginning of the line:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift DispatchQueue.main.async { ocean.add("dolphins") ocean.add("whales") } await expect(ocean).toEventually(contain("dolphens", "whiles"))"><pre>// Swift <span class="pl-smi">DispatchQueue</span><span class="pl-kos">.</span>main<span class="pl-kos">.</span><span class="pl-en"><span class="pl-k">async</span></span> <span class="pl-kos">{</span> ocean<span class="pl-kos">.</span><span class="pl-en">add</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphins</span><span class="pl-s">"</span><span class="pl-kos">)</span> ocean<span class="pl-kos">.</span><span class="pl-en">add</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">whales</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">await</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphens</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">whiles</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Starting in Nimble 12, <code>toEventually</code> et. al. now also supports async expectations. For example, the following test is now supported:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="actor MyActor { private var counter = 0 func access() -> Int { counter += 1 return counter } } let subject = MyActor() await expect { await subject.access() }.toEventually(equal(2))"><pre><span class="pl-k">actor</span> <span class="pl-smi">MyActor</span> <span class="pl-kos">{</span> <span class="pl-k">private</span> <span class="pl-k">var</span> <span class="pl-s1"><span class="pl-c1">counter</span></span> <span class="pl-c1">=</span> <span class="pl-c1">0</span> <span class="pl-en">func</span> access<span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Int</span> <span class="pl-kos">{</span> counter <span class="pl-c1">+=</span> <span class="pl-c1">1</span> <span class="pl-k">return</span> counter <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">let</span> <span class="pl-s1">subject</span> <span class="pl-c1">=</span> <span class="pl-en">MyActor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">await</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-k">await</span> subject<span class="pl-kos">.</span><span class="pl-en">access</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Verifying a Matcher will Never or Always Match</h3><a id="user-content-verifying-a-matcher-will-never-or-always-match" class="anchor" aria-label="Permalink: Verifying a Matcher will Never or Always Match" href="#verifying-a-matcher-will-never-or-always-match"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">You can also test that a value always or never matches throughout the length of the timeout. Use <code>toNever</code> and <code>toAlways</code> for this:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift ocean.add("dolphins") expect(ocean).toAlways(contain("dolphins")) expect(ocean).toNever(contain("hares"))"><pre>// Swift ocean<span class="pl-kos">.</span><span class="pl-en">add</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphins</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toAlways</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphins</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNever</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">hares</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C [ocean add:@"dolphins"] expect(ocean).toAlways(contain(@"dolphins")) expect(ocean).toNever(contain(@"hares"))"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> [ocean <span class="pl-c1">add:</span><span class="pl-s"><span class="pl-pds">@"</span>dolphins<span class="pl-pds">"</span></span>] <span class="pl-en">expect</span>(ocean).toAlways(contain(<span class="pl-s"><span class="pl-pds">@"</span>dolphins<span class="pl-pds">"</span></span>)) expect(ocean).toNever(contain(<span class="pl-s"><span class="pl-pds">@"</span>hares<span class="pl-pds">"</span></span>))</pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Waiting for a Callback to be Called</h3><a id="user-content-waiting-for-a-callback-to-be-called" class="anchor" aria-label="Permalink: Waiting for a Callback to be Called" href="#waiting-for-a-callback-to-be-called"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">You can also provide a callback by using the <code>waitUntil</code> function:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift waitUntil { done in ocean.goFish { success in expect(success).to(beTrue()) done() } }"><pre>// Swift <span class="pl-en">waitUntil</span> <span class="pl-kos">{</span> done <span class="pl-k">in</span> ocean<span class="pl-kos">.</span><span class="pl-en">goFish</span> <span class="pl-kos">{</span> success <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>success<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beTrue</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">done</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C waitUntil(^(void (^done)(void)){ [ocean goFishWithHandler:^(BOOL success){ expect(success).to(beTrue()); done(); }]; });"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">waitUntil</span>(^(<span class="pl-k">void</span> (^done)(<span class="pl-k">void</span>)){ [ocean <span class="pl-c1">goFishWithHandler:</span>^(<span class="pl-c1">BOOL</span> success){ <span class="pl-c1">expect</span>(success).<span class="pl-c1">to</span>(<span class="pl-c1">beTrue</span>()); <span class="pl-c1">done</span>(); }]; });</pre></div> <p dir="auto"><code>waitUntil</code> also optionally takes a timeout parameter:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift waitUntil(timeout: .seconds(10)) { done in ocean.goFish { success in expect(success).to(beTrue()) done() } }"><pre>// Swift <span class="pl-en">waitUntil</span><span class="pl-kos">(</span>timeout<span class="pl-kos">:</span> <span class="pl-kos">.</span>seconds<span class="pl-kos">(</span><span class="pl-c1">10</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> done <span class="pl-k">in</span> ocean<span class="pl-kos">.</span><span class="pl-en">goFish</span> <span class="pl-kos">{</span> success <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>success<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beTrue</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">done</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C waitUntilTimeout(10, ^(void (^done)(void)){ [ocean goFishWithHandler:^(BOOL success){ expect(success).to(beTrue()); done(); }]; });"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">waitUntilTimeout</span>(<span class="pl-c1">10</span>, ^(<span class="pl-k">void</span> (^done)(<span class="pl-k">void</span>)){ [ocean <span class="pl-c1">goFishWithHandler:</span>^(<span class="pl-c1">BOOL</span> success){ <span class="pl-c1">expect</span>(success).<span class="pl-c1">to</span>(<span class="pl-c1">beTrue</span>()); <span class="pl-c1">done</span>(); }]; });</pre></div> <p dir="auto">Note: <code>waitUntil</code> triggers its timeout code on the main thread. Blocking the main thread will cause Nimble to stop the run loop to continue. This can cause test pollution for whatever incomplete code that was running on the main thread. Blocking the main thread can be caused by blocking IO, calls to sleep(), deadlocks, and synchronous IPC.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Changing the Timeout and Polling Intervals</h3><a id="user-content-changing-the-timeout-and-polling-intervals" class="anchor" aria-label="Permalink: Changing the Timeout and Polling Intervals" href="#changing-the-timeout-and-polling-intervals"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Sometimes it takes more than a second for a value to update. In those cases, use the <code>timeout</code> parameter:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Waits three seconds for ocean to contain "starfish": expect(ocean).toEventually(contain("starfish"), timeout: .seconds(3)) // Evaluate someValue every 0.2 seconds repeatedly until it equals 100, or fails if it timeouts after 5.5 seconds. expect(someValue).toEventually(equal(100), timeout: .milliseconds(5500), pollInterval: .milliseconds(200))"><pre>// Swift // Waits three seconds for ocean to contain "starfish": <span class="pl-en">expect</span><span class="pl-kos">(</span>ocean<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">starfish</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">,</span> timeout<span class="pl-kos">:</span> <span class="pl-kos">.</span>seconds<span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Evaluate someValue every 0.2 seconds repeatedly until it equals 100, or fails if it timeouts after 5.5 seconds. <span class="pl-en">expect</span><span class="pl-kos">(</span>someValue<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span><span class="pl-kos">,</span> timeout<span class="pl-kos">:</span> <span class="pl-kos">.</span>milliseconds<span class="pl-kos">(</span><span class="pl-c1">5500</span><span class="pl-kos">)</span><span class="pl-kos">,</span> pollInterval<span class="pl-kos">:</span> <span class="pl-kos">.</span>milliseconds<span class="pl-kos">(</span><span class="pl-c1">200</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Waits three seconds for ocean to contain "starfish": expect(ocean).withTimeout(3).toEventually(contain(@"starfish"));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Waits three seconds for ocean to contain "starfish":</span> <span class="pl-en">expect</span>(ocean).withTimeout(<span class="pl-c1">3</span>).toEventually(contain(<span class="pl-s"><span class="pl-pds">@"</span>starfish<span class="pl-pds">"</span></span>));</pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Changing default Timeout and Poll Intervals</h3><a id="user-content-changing-default-timeout-and-poll-intervals" class="anchor" aria-label="Permalink: Changing default Timeout and Poll Intervals" href="#changing-default-timeout-and-poll-intervals"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In some cases (e.g. when running on slower machines) it can be useful to modify the default timeout and poll interval values. This can be done as follows:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Increase the global timeout to 5 seconds: Nimble.PollingDefaults.timeout = .seconds(5) // Slow the polling interval to 0.1 seconds: Nimble.PollingDefaults.pollInterval = .milliseconds(100)"><pre>// Swift // Increase the global timeout to 5 seconds: <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>timeout <span class="pl-c1">=</span> <span class="pl-kos">.</span>seconds<span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span> // Slow the polling interval to 0.1 seconds: <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>pollInterval <span class="pl-c1">=</span> <span class="pl-kos">.</span>milliseconds<span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span></pre></div> <p dir="auto">You can set these globally at test startup in two ways:</p> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">Quick</h4><a id="user-content-quick" class="anchor" aria-label="Permalink: Quick" href="#quick"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If you use <a href="https://github.com/Quick/Quick">Quick</a>, add a <a href="https://github.com/Quick/Quick/blob/main/Documentation/en-us/ConfiguringQuick.md"><code>QuickConfiguration</code> subclass</a> which sets your desired <code>PollingDefaults</code>.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import Quick import Nimble class PollingConfiguration: QuickConfiguration { override class func configure(_ configuration: QCKConfiguration) { Nimble.PollingDefaults.timeout = .seconds(5) Nimble.PollingDefaults.pollInterval = .milliseconds(100) } }"><pre><span class="pl-k">import</span> Quick <span class="pl-k">import</span> Nimble <span class="pl-k">class</span> <span class="pl-smi">PollingConfiguration</span><span class="pl-kos">:</span> <span class="pl-smi">QuickConfiguration</span> <span class="pl-kos">{</span> <span class="pl-k"><span class="pl-k">override</span></span> <span class="pl-k"><span class="pl-k">class</span></span> <span class="pl-en">func</span> configure<span class="pl-kos">(</span>_ configuration<span class="pl-kos">:</span> <span class="pl-smi">QCKConfiguration</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>timeout <span class="pl-c1">=</span> <span class="pl-kos">.</span>seconds<span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span> <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>pollInterval <span class="pl-c1">=</span> <span class="pl-kos">.</span>milliseconds<span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="markdown-heading" dir="auto"><h4 tabindex="-1" class="heading-element" dir="auto">XCTest</h4><a id="user-content-xctest" class="anchor" aria-label="Permalink: XCTest" href="#xctest"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If you use <a href="https://developer.apple.com/documentation/xctest" rel="nofollow">XCTest</a>, add an object that conforms to <a href="https://developer.apple.com/documentation/xctest/xctestobservation" rel="nofollow"><code>XCTestObservation</code></a> and implement <a href="https://developer.apple.com/documentation/xctest/xctestobservation/1500772-testbundlewillstart" rel="nofollow"><code>testBundleWillStart(_:)</code></a>.</p> <p dir="auto">Additionally, you will need to register this observer with the <a href="https://developer.apple.com/documentation/xctest/xctestobservationcenter" rel="nofollow"><code>XCTestObservationCenter</code></a> at test startup. To do this, set the <code>NSPrincipalClass</code> key in your test bundle's Info.plist and implement a class with that same name.</p> <p dir="auto">For example</p> <div class="highlight highlight-text-xml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="<!-- Info.plist --> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <!-- ... --> <key>NSPrincipalClass</key> <string>MyTests.TestSetup</string> </dict> </plist>"><pre><span class="pl-c"><span class="pl-c"><!--</span> Info.plist <span class="pl-c">--></span></span> <?<span class="pl-ent">xml</span><span class="pl-e"> version</span>=<span class="pl-s"><span class="pl-pds">"</span>1.0<span class="pl-pds">"</span></span><span class="pl-e"> encoding</span>=<span class="pl-s"><span class="pl-pds">"</span>UTF-8<span class="pl-pds">"</span></span>?> <!<span class="pl-ent">DOCTYPE</span> <span class="pl-e">plist</span> PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <<span class="pl-ent">plist</span> <span class="pl-e">version</span>=<span class="pl-s"><span class="pl-pds">"</span>1.0<span class="pl-pds">"</span></span>> <<span class="pl-ent">dict</span>> <span class="pl-c"><span class="pl-c"><!--</span> ... <span class="pl-c">--></span></span> <<span class="pl-ent">key</span>>NSPrincipalClass</<span class="pl-ent">key</span>> <<span class="pl-ent">string</span>>MyTests.TestSetup</<span class="pl-ent">string</span>> </<span class="pl-ent">dict</span>> </<span class="pl-ent">plist</span>></pre></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// TestSetup.swift import XCTest import Nimble @objc class TestSetup: NSObject { override init() { XCTestObservationCenter.shared.register(PollingConfigurationTestObserver()) } } class PollingConfigurationTestObserver: NSObject, XCTestObserver { func testBundleWillStart(_ testBundle: Bundle) { Nimble.PollingDefaults.timeout = .seconds(5) Nimble.PollingDefaults.pollInterval = .milliseconds(100) } }"><pre>// TestSetup.swift <span class="pl-k">import</span> XCTest <span class="pl-k">import</span> Nimble <span class="pl-s1">@<span class="pl-smi">objc</span></span> <span class="pl-k">class</span> <span class="pl-smi">TestSetup</span><span class="pl-kos">:</span> <span class="pl-smi">NSObject</span> <span class="pl-kos">{</span> <span class="pl-k"><span class="pl-k">override</span></span> <span class="pl-v">init</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">XCTestObservationCenter</span><span class="pl-kos">.</span>shared<span class="pl-kos">.</span><span class="pl-en">register</span><span class="pl-kos">(</span><span class="pl-en">PollingConfigurationTestObserver</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-smi">PollingConfigurationTestObserver</span><span class="pl-kos">:</span> <span class="pl-smi">NSObject</span><span class="pl-kos">,</span> <span class="pl-smi">XCTestObserver</span> <span class="pl-kos">{</span> <span class="pl-en">func</span> testBundleWillStart<span class="pl-kos">(</span>_ testBundle<span class="pl-kos">:</span> <span class="pl-smi">Bundle</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>timeout <span class="pl-c1">=</span> <span class="pl-kos">.</span>seconds<span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span> <span class="pl-smi">Nimble</span><span class="pl-kos">.</span>PollingDefaults<span class="pl-kos">.</span>pollInterval <span class="pl-c1">=</span> <span class="pl-kos">.</span>milliseconds<span class="pl-kos">(</span><span class="pl-c1">100</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">In Linux, you can implement <code>LinuxMain</code> to set the PollingDefaults before calling <code>XCTMain</code>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Objective-C Support</h2><a id="user-content-objective-c-support" class="anchor" aria-label="Permalink: Objective-C Support" href="#objective-c-support"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble has full support for Objective-C. However, there are two things to keep in mind when using Nimble in Objective-C:</p> <ol dir="auto"> <li> <p dir="auto">All parameters passed to the <code>expect</code> function, as well as matcher functions like <code>equal</code>, must be Objective-C objects or can be converted into an <code>NSObject</code> equivalent:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C @import Nimble; expect(@(1 + 1)).to(equal(@2)); expect(@"Hello world").to(contain(@"world")); // Boxed as NSNumber * expect(2).to(equal(2)); expect(1.2).to(beLessThan(2.0)); expect(true).to(beTruthy()); // Boxed as NSString * expect("Hello world").to(equal("Hello world")); // Boxed as NSRange expect(NSMakeRange(1, 10)).to(equal(NSMakeRange(1, 10)));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> @import Nimble; <span class="pl-en">expect</span>(@(<span class="pl-c1">1</span> + <span class="pl-c1">1</span>)).to(equal(@<span class="pl-c1">2</span>)); <span class="pl-en">expect</span>(<span class="pl-s"><span class="pl-pds">@"</span>Hello world<span class="pl-pds">"</span></span>).to(contain(<span class="pl-s"><span class="pl-pds">@"</span>world<span class="pl-pds">"</span></span>)); <span class="pl-c"><span class="pl-c">//</span> Boxed as NSNumber *</span> <span class="pl-en">expect</span>(<span class="pl-c1">2</span>).to(equal(<span class="pl-c1">2</span>)); <span class="pl-en">expect</span>(<span class="pl-c1">1.2</span>).to(beLessThan(<span class="pl-c1">2.0</span>)); <span class="pl-en">expect</span>(<span class="pl-c1">true</span>).to(beTruthy()); <span class="pl-c"><span class="pl-c">//</span> Boxed as NSString *</span> <span class="pl-en">expect</span>(<span class="pl-s"><span class="pl-pds">"</span>Hello world<span class="pl-pds">"</span></span>).to(equal(<span class="pl-s"><span class="pl-pds">"</span>Hello world<span class="pl-pds">"</span></span>)); <span class="pl-c"><span class="pl-c">//</span> Boxed as NSRange</span> <span class="pl-en">expect</span>(<span class="pl-c1">NSMakeRange</span>(<span class="pl-c1">1</span>, <span class="pl-c1">10</span>)).to(equal(<span class="pl-c1">NSMakeRange</span>(<span class="pl-c1">1</span>, <span class="pl-c1">10</span>)));</pre></div> </li> <li> <p dir="auto">To make an expectation on an expression that does not return a value, such as <code>-[NSException raise]</code>, use <code>expectAction</code> instead of <code>expect</code>:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expectAction(^{ [exception raise]; }).to(raiseException());"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expectAction</span>(^{ [<span class="pl-c1">exception</span> <span class="pl-c1">raise</span>]; }).to(raiseException());</pre></div> </li> </ol> <p dir="auto">The following types are currently converted to an <code>NSObject</code> type:</p> <ul dir="auto"> <li><strong>C Numeric types</strong> are converted to <code>NSNumber *</code></li> <li><code>NSRange</code> is converted to <code>NSValue *</code></li> <li><code>char *</code> is converted to <code>NSString *</code></li> </ul> <p dir="auto">For the following matchers:</p> <ul dir="auto"> <li><code>equal</code></li> <li><code>beGreaterThan</code></li> <li><code>beGreaterThanOrEqual</code></li> <li><code>beLessThan</code></li> <li><code>beLessThanOrEqual</code></li> <li><code>beCloseTo</code></li> <li><code>beTrue</code></li> <li><code>beFalse</code></li> <li><code>beTruthy</code></li> <li><code>beFalsy</code></li> <li><code>haveCount</code></li> </ul> <p dir="auto">If you would like to see more, <a href="https://github.com/Quick/Nimble/issues">file an issue</a>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Disabling Objective-C Shorthand</h2><a id="user-content-disabling-objective-c-shorthand" class="anchor" aria-label="Permalink: Disabling Objective-C Shorthand" href="#disabling-objective-c-shorthand"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble provides a shorthand for expressing expectations using the <code>expect</code> function. To disable this shorthand in Objective-C, define the <code>NIMBLE_DISABLE_SHORT_SYNTAX</code> macro somewhere in your code before importing Nimble:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#define NIMBLE_DISABLE_SHORT_SYNTAX 1 @import Nimble; NMB_expect(^{ return seagull.squawk; }, __FILE__, __LINE__).to(NMB_equal(@"Squee!"));"><pre>#<span class="pl-k">define</span> <span class="pl-en">NIMBLE_DISABLE_SHORT_SYNTAX</span> <span class="pl-c1">1</span> @import Nimble; <span class="pl-en">NMB_expect</span>(^{ <span class="pl-k">return</span> seagull.<span class="pl-smi">squawk</span>; }, __FILE__, __LINE__).to(NMB_equal(<span class="pl-s"><span class="pl-pds">@"</span>Squee!<span class="pl-pds">"</span></span>));</pre></div> <blockquote> <p dir="auto">Disabling the shorthand is useful if you're testing functions with names that conflict with Nimble functions, such as <code>expect</code> or <code>equal</code>. If that's not the case, there's no point in disabling the shorthand.</p> </blockquote> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Using <code>require</code> to demand that a matcher pass before continuing</h1><a id="user-content-using-require-to-demand-that-a-matcher-pass-before-continuing" class="anchor" aria-label="Permalink: Using require to demand that a matcher pass before continuing" href="#using-require-to-demand-that-a-matcher-pass-before-continuing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble 13.1 added the <code>require</code> dsl to complement <code>expect</code>. <code>require</code> looks similar to <code>expect</code> and works with matchers just like <code>expect</code> does. The difference is that <code>require</code> requires that the matcher passes - if the matcher doesn't pass, then <code>require</code> will throw an error. Additionally, if <code>require</code> does pass, then it'll return the result of running the expression.</p> <p dir="auto">For example, in testing a function that returns an array, you might need to first guarantee that there are exactly 3 items in the array before continuing to assert on it. Instead of writing code that needlessly duplicates an assertion and a conditional like so:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let collection = myFunction() expect(collection).to(haveCount(3)) guard collection.count == 3 else { return } // ..."><pre><span class="pl-k">let</span> <span class="pl-s1">collection</span> <span class="pl-c1">=</span> <span class="pl-en">myFunction</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>collection<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">haveCount</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-k">guard</span> collection<span class="pl-kos">.</span>count <span class="pl-c1">==</span> <span class="pl-c1">3</span> <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-kos">}</span> // ...</pre></div> <p dir="auto">You can replace that with:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let collection = try require(myFunction()).to(haveCount(3)) // ..."><pre><span class="pl-k">let</span> <span class="pl-s1">collection</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-en">myFunction</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">haveCount</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // ...</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Polling with <code>require</code>.</h2><a id="user-content-polling-with-require" class="anchor" aria-label="Permalink: Polling with require." href="#polling-with-require"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Because <code>require</code> does everything you can do with <code>expect</code>, you can also use <code>require</code> to <a href="#polling-expectations">poll matchers</a> using <code>toEventually</code>, <code>eventuallyTo</code>, <code>toEventuallyNot</code>, <code>toNotEventually</code>, <code>toNever</code>, <code>neverTo</code>, <code>toAlways</code>, and <code>alwaysTo</code>. These work exactly the same as they do when using <code>expect</code>, except that they throw if they fail, and they return the value of the expression when they pass.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Using <code>require</code> with Async expressions and Async matchers</h2><a id="user-content-using-require-with-async-expressions-and-async-matchers" class="anchor" aria-label="Permalink: Using require with Async expressions and Async matchers" href="#using-require-with-async-expressions-and-async-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><code>require</code> also works with both async expressions (<code>require { await someExpression() }.to(...)</code>), and async matchers (<code>require().to(someAsyncMatcher())</code>).</p> <p dir="auto">Note that to prevent compiler confusion, you cannot use <code>require</code> with async autoclosures. That is, <code>require(await someExpression())</code> will not compile. You can instead either make the closure explicit (<code>require { await someExpression() }</code>), or use the <code>requirea</code> function, which does accept autoclosures. Similarly, if you ever wish to use the sync version of <code>require</code> when the compiler is trying to force you to use the async version, you can use the <code>requires</code> function, which only allows synchronous expressions.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Using <code>unwrap</code> to replace <code>require(...).toNot(beNil())</code></h2><a id="user-content-using-unwrap-to-replace-requiretonotbenil" class="anchor" aria-label="Permalink: Using unwrap to replace require(...).toNot(beNil())" href="#using-unwrap-to-replace-requiretonotbenil"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">It's very common to require that a value not be nil. Instead of writing <code>try require(...).toNot(beNil())</code>, Nimble provides the <code>unwrap</code> function. This expression throws an error if the expression evaluates to nil, or returns the non-nil result when it passes. For example:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let value = try unwrap(nil as Int?) // throws let value = try unwrap(1 as Int?) // returns 1"><pre><span class="pl-k">let</span> <span class="pl-s1">value</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">unwrap</span><span class="pl-kos">(</span><span class="pl-smi">nil</span> <span class="pl-k">as</span> <span class="pl-smi">Int</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-kos">)</span> // throws <span class="pl-k">let</span> <span class="pl-s1">value</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">unwrap</span><span class="pl-kos">(</span><span class="pl-c1">1</span> <span class="pl-k">as</span> <span class="pl-smi">Int</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-kos">)</span> // returns 1</pre></div> <p dir="auto">Additionally, there is also the <code>pollUnwrap</code> function, which aliases to <code>require(...).toEventuallyNot(beNil())</code>. This is extremely useful for verifying that a value that is updated on a background thread was eventually set to a non-nil value.</p> <p dir="auto">Note: As with <code>require</code>, there are <code>unwraps</code>, <code>unwrapa</code>, <code>pollUnwraps</code>, and <code>pollUnwrapa</code> variants for allowing you to use autoclosures specifically with synchronous or asynchronous code.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Throwing a Custom Error from Require</h2><a id="user-content-throwing-a-custom-error-from-require" class="anchor" aria-label="Permalink: Throwing a Custom Error from Require" href="#throwing-a-custom-error-from-require"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">By default, if the matcher fails in a <code>require</code>, then a <code>RequireError</code> will be thrown. You can override this behavior and throw a custom error by passing a non-nil <code>Error</code> value to the <code>customError</code> parameter:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="try require(1).to(equal(2)) // throws a `RequireError` try require(customError: MyCustomError(), 1).to(equal(2)) // throws a `MyCustomError`"><pre><span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // throws a `RequireError` <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">require</span><span class="pl-kos">(</span>customError<span class="pl-kos">:</span> <span class="pl-en">MyCustomError</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // throws a `MyCustomError`</pre></div> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Built-in Matcher Functions</h1><a id="user-content-built-in-matcher-functions" class="anchor" aria-label="Permalink: Built-in Matcher Functions" href="#built-in-matcher-functions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble includes a wide variety of matcher functions.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Type Checking</h2><a id="user-content-type-checking" class="anchor" aria-label="Permalink: Type Checking" href="#type-checking"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble supports checking the type membership of any kind of object, whether Objective-C conformant or not:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift protocol SomeProtocol{} class SomeClassConformingToProtocol: SomeProtocol{} struct SomeStructConformingToProtocol: SomeProtocol{} // The following tests pass expect(1).to(beAKindOf(Int.self)) expect("turtle").to(beAKindOf(String.self)) let classObject = SomeClassConformingToProtocol() expect(classObject).to(beAKindOf(SomeProtocol.self)) expect(classObject).to(beAKindOf(SomeClassConformingToProtocol.self)) expect(classObject).toNot(beAKindOf(SomeStructConformingToProtocol.self)) let structObject = SomeStructConformingToProtocol() expect(structObject).to(beAKindOf(SomeProtocol.self)) expect(structObject).to(beAKindOf(SomeStructConformingToProtocol.self)) expect(structObject).toNot(beAKindOf(SomeClassConformingToProtocol.self))"><pre>// Swift <span class="pl-k">protocol</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">:</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">struct</span> <span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">:</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> // The following tests pass <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">Int</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">turtle</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">String</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">classObject</span> <span class="pl-c1">=</span> <span class="pl-en">SomeClassConformingToProtocol</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">structObject</span> <span class="pl-c1">=</span> <span class="pl-en">SomeStructConformingToProtocol</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // The following tests pass NSMutableArray *array = [NSMutableArray array]; expect(array).to(beAKindOf([NSArray class])); expect(@1).toNot(beAKindOf([NSNull class]));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> The following tests pass</span> <span class="pl-c1">NSMutableArray</span> *array = [<span class="pl-c1">NSMutableArray</span> <span class="pl-c1">array</span>]; <span class="pl-en">expect</span>(array).to(beAKindOf([<span class="pl-c1">NSArray</span> <span class="pl-c1">class</span>])); <span class="pl-en">expect</span>(@<span class="pl-c1">1</span>).toNot(beAKindOf([<span class="pl-c1">NSNull</span> <span class="pl-c1">class</span>]));</pre></div> <p dir="auto">Objects can be tested for their exact types using the <code>beAnInstanceOf</code> matcher:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift protocol SomeProtocol{} class SomeClassConformingToProtocol: SomeProtocol{} struct SomeStructConformingToProtocol: SomeProtocol{} // Unlike the 'beKindOf' matcher, the 'beAnInstanceOf' matcher only // passes if the object is the EXACT type requested. The following // tests pass -- note its behavior when working in an inheritance hierarchy. expect(1).to(beAnInstanceOf(Int.self)) expect("turtle").to(beAnInstanceOf(String.self)) let classObject = SomeClassConformingToProtocol() expect(classObject).toNot(beAnInstanceOf(SomeProtocol.self)) expect(classObject).to(beAnInstanceOf(SomeClassConformingToProtocol.self)) expect(classObject).toNot(beAnInstanceOf(SomeStructConformingToProtocol.self)) let structObject = SomeStructConformingToProtocol() expect(structObject).toNot(beAnInstanceOf(SomeProtocol.self)) expect(structObject).to(beAnInstanceOf(SomeStructConformingToProtocol.self)) expect(structObject).toNot(beAnInstanceOf(SomeClassConformingToProtocol.self))"><pre>// Swift <span class="pl-k">protocol</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">class</span> <span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">:</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> <span class="pl-k">struct</span> <span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">:</span> <span class="pl-smi">SomeProtocol</span><span class="pl-kos">{</span><span class="pl-kos">}</span> // Unlike the 'beKindOf' matcher, the 'beAnInstanceOf' matcher only // passes if the object is the EXACT type requested. The following // tests pass -- note its behavior when working in an inheritance hierarchy. <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">Int</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">turtle</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">String</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">classObject</span> <span class="pl-c1">=</span> <span class="pl-en">SomeClassConformingToProtocol</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>classObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">structObject</span> <span class="pl-c1">=</span> <span class="pl-en">SomeStructConformingToProtocol</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeStructConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>structObject<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span><span class="pl-smi">SomeClassConformingToProtocol</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Equivalence</h2><a id="user-content-equivalence" class="anchor" aria-label="Permalink: Equivalence" href="#equivalence"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'actual' is equivalent to 'expected': expect(actual).to(equal(expected)) expect(actual) == expected // Passes if 'actual' is not equivalent to 'expected': expect(actual).toNot(equal(expected)) expect(actual) != expected"><pre>// Swift // Passes if 'actual' is equivalent to 'expected': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">==</span> expected // Passes if 'actual' is not equivalent to 'expected': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">!=</span> expected</pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual' is equivalent to 'expected': expect(actual).to(equal(expected)) // Passes if 'actual' is not equivalent to 'expected': expect(actual).toNot(equal(expected))"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is equivalent to 'expected':</span> <span class="pl-en">expect</span>(actual).to(equal(expected)) <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is not equivalent to 'expected':</span> expect(actual).toNot(equal(expected))</pre></div> <p dir="auto">Values must be <code>Equatable</code>, <code>Comparable</code>, or subclasses of <code>NSObject</code>. <code>equal</code> will always fail when used to compare one or more <code>nil</code> values.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Identity</h2><a id="user-content-identity" class="anchor" aria-label="Permalink: Identity" href="#identity"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'actual' has the same pointer address as 'expected': expect(actual).to(beIdenticalTo(expected)) expect(actual) === expected // Passes if 'actual' does not have the same pointer address as 'expected': expect(actual).toNot(beIdenticalTo(expected)) expect(actual) !== expected"><pre>// Swift // Passes if 'actual' has the same pointer address as 'expected': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beIdenticalTo</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">===</span> expected // Passes if 'actual' does not have the same pointer address as 'expected': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beIdenticalTo</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">!==</span> expected</pre></div> <p dir="auto">It is important to remember that <code>beIdenticalTo</code> only makes sense when comparing types with reference semantics, which have a notion of identity. In Swift, that means types that are defined as a <code>class</code>.</p> <p dir="auto">This matcher will not work when comparing types with value semantics such as those defined as a <code>struct</code> or <code>enum</code>. If you need to compare two value types, consider what it means for instances of your type to be identical. This may mean comparing individual properties or, if it makes sense to do so, conforming your type to <code>Equatable</code> and using Nimble's equivalence matchers instead.</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual' has the same pointer address as 'expected': expect(actual).to(beIdenticalTo(expected)); // Passes if 'actual' does not have the same pointer address as 'expected': expect(actual).toNot(beIdenticalTo(expected));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' has the same pointer address as 'expected':</span> <span class="pl-en">expect</span>(actual).to(beIdenticalTo(expected)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' does not have the same pointer address as 'expected':</span> <span class="pl-en">expect</span>(actual).toNot(beIdenticalTo(expected));</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Comparisons</h2><a id="user-content-comparisons" class="anchor" aria-label="Permalink: Comparisons" href="#comparisons"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(actual).to(beLessThan(expected)) expect(actual) < expected expect(actual).to(beLessThanOrEqualTo(expected)) expect(actual) <= expected expect(actual).to(beGreaterThan(expected)) expect(actual) > expected expect(actual).to(beGreaterThanOrEqualTo(expected)) expect(actual) >= expected"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beLessThan</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1"><</span> expected <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beLessThanOrEqualTo</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1"><=</span> expected <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beGreaterThan</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">></span> expected <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beGreaterThanOrEqualTo</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">>=</span> expected</pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(actual).to(beLessThan(expected)); expect(actual).to(beLessThanOrEqualTo(expected)); expect(actual).to(beGreaterThan(expected)); expect(actual).to(beGreaterThanOrEqualTo(expected));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(actual).to(beLessThan(expected)); <span class="pl-en">expect</span>(actual).to(beLessThanOrEqualTo(expected)); <span class="pl-en">expect</span>(actual).to(beGreaterThan(expected)); <span class="pl-en">expect</span>(actual).to(beGreaterThanOrEqualTo(expected));</pre></div> <blockquote> <p dir="auto">Values given to the comparison matchers above must implement <code>Comparable</code>.</p> </blockquote> <p dir="auto">Because of how computers represent floating point numbers, assertions that two floating point numbers be equal will sometimes fail. To express that two numbers should be close to one another within a certain margin of error, use <code>beCloseTo</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(actual).to(beCloseTo(expected, within: delta))"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beCloseTo</span><span class="pl-kos">(</span>expected<span class="pl-kos">,</span> within<span class="pl-kos">:</span> delta<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(actual).to(beCloseTo(expected).within(delta));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(actual).to(beCloseTo(expected).within(delta));</pre></div> <p dir="auto">For example, to assert that <code>10.01</code> is close to <code>10</code>, you can write:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(10.01).to(beCloseTo(10, within: 0.1))"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">10.01</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beCloseTo</span><span class="pl-kos">(</span><span class="pl-c1">10</span><span class="pl-kos">,</span> within<span class="pl-kos">:</span> <span class="pl-c1">0.1</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(@(10.01)).to(beCloseTo(@10).within(0.1));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(@(<span class="pl-c1">10.01</span>)).to(beCloseTo(@<span class="pl-c1">10</span>).within(<span class="pl-c1">0.1</span>));</pre></div> <p dir="auto">There is also an operator shortcut available in Swift:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(actual) ≈ expected expect(actual) ≈ (expected, delta) "><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">≈</span> expected <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">≈</span> <span class="pl-kos">(</span>expected<span class="pl-kos">,</span> delta<span class="pl-kos">)</span></pre></div> <p dir="auto">(Type <kbd>option</kbd>+<kbd>x</kbd> to get <code>≈</code> on a U.S. keyboard)</p> <p dir="auto">The former version uses the default delta of 0.0001. Here is yet another way to do this:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(actual) ≈ expected ± delta expect(actual) == expected ± delta "><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">≈</span> expected <span class="pl-c1">±</span> delta <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span> <span class="pl-c1">==</span> expected <span class="pl-c1">±</span> delta</pre></div> <p dir="auto">(Type <kbd>option</kbd>+<kbd>shift</kbd>+<kbd>=</kbd> to get <code>±</code> on a U.S. keyboard)</p> <p dir="auto">If you are comparing arrays of floating point numbers, you'll find the following useful:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect([0.0, 2.0]) ≈ [0.0001, 2.0001] expect([0.0, 2.0]).to(beCloseTo([0.1, 2.1], within: 0.1)) "><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">0.0</span><span class="pl-kos">,</span> <span class="pl-c1">2.0</span><span class="pl-kos">]</span><span class="pl-kos">)</span> <span class="pl-c1">≈</span> <span class="pl-kos">[</span><span class="pl-c1">0.0001</span><span class="pl-kos">,</span> <span class="pl-c1">2.0001</span><span class="pl-kos">]</span> <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">0.0</span><span class="pl-kos">,</span> <span class="pl-c1">2.0</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beCloseTo</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">0.1</span><span class="pl-kos">,</span> <span class="pl-c1">2.1</span><span class="pl-kos">]</span><span class="pl-kos">,</span> within<span class="pl-kos">:</span> <span class="pl-c1">0.1</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <blockquote> <p dir="auto">Values given to the <code>beCloseTo</code> matcher must conform to <code>FloatingPoint</code>.</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Types/Classes</h2><a id="user-content-typesclasses" class="anchor" aria-label="Permalink: Types/Classes" href="#typesclasses"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'instance' is an instance of 'aClass': expect(instance).to(beAnInstanceOf(aClass)) // Passes if 'instance' is an instance of 'aClass' or any of its subclasses: expect(instance).to(beAKindOf(aClass))"><pre>// Swift // Passes if 'instance' is an instance of 'aClass': <span class="pl-en">expect</span><span class="pl-kos">(</span>instance<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAnInstanceOf</span><span class="pl-kos">(</span>aClass<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'instance' is an instance of 'aClass' or any of its subclasses: <span class="pl-en">expect</span><span class="pl-kos">(</span>instance<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span>aClass<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'instance' is an instance of 'aClass': expect(instance).to(beAnInstanceOf(aClass)); // Passes if 'instance' is an instance of 'aClass' or any of its subclasses: expect(instance).to(beAKindOf(aClass));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'instance' is an instance of 'aClass':</span> <span class="pl-en">expect</span>(instance).to(beAnInstanceOf(aClass)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'instance' is an instance of 'aClass' or any of its subclasses:</span> <span class="pl-en">expect</span>(instance).to(beAKindOf(aClass));</pre></div> <blockquote> <p dir="auto">Instances must be Objective-C objects: subclasses of <code>NSObject</code>, or Swift objects bridged to Objective-C with the <code>@objc</code> prefix.</p> </blockquote> <p dir="auto">For example, to assert that <code>dolphin</code> is a kind of <code>Mammal</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(dolphin).to(beAKindOf(Mammal))"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span>dolphin<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beAKindOf</span><span class="pl-kos">(</span>Mammal<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(dolphin).to(beAKindOf([Mammal class]));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(dolphin).to(beAKindOf([Mammal <span class="pl-c1">class</span>]));</pre></div> <blockquote> <p dir="auto"><code>beAnInstanceOf</code> uses the <code>-[NSObject isMemberOfClass:]</code> method to test membership. <code>beAKindOf</code> uses <code>-[NSObject isKindOfClass:]</code>.</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Truthiness</h2><a id="user-content-truthiness" class="anchor" aria-label="Permalink: Truthiness" href="#truthiness"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Passes if 'actual' is not nil, true, or an object with a boolean value of true: expect(actual).to(beTruthy()) // Passes if 'actual' is only true (not nil or an object conforming to Boolean true): expect(actual).to(beTrue()) // Passes if 'actual' is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()) // Passes if 'actual' is only false (not nil or an object conforming to Boolean false): expect(actual).to(beFalse()) // Passes if 'actual' is nil: expect(actual).to(beNil())"><pre>// Passes if 'actual' is not nil, true, or an object with a boolean value of true: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beTruthy</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' is only true (not nil or an object conforming to Boolean true): <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beTrue</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' is nil, false, or an object with a boolean value of false: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beFalsy</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' is only false (not nil or an object conforming to Boolean false): <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beFalse</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' is nil: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beNil</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual' is not nil, true, or an object with a boolean value of true: expect(actual).to(beTruthy()); // Passes if 'actual' is only true (not nil or an object conforming to Boolean true): expect(actual).to(beTrue()); // Passes if 'actual' is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()); // Passes if 'actual' is only false (not nil or an object conforming to Boolean false): expect(actual).to(beFalse()); // Passes if 'actual' is nil: expect(actual).to(beNil());"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is not nil, true, or an object with a boolean value of true:</span> <span class="pl-en">expect</span>(actual).to(beTruthy()); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is only true (not nil or an object conforming to Boolean true):</span> <span class="pl-en">expect</span>(actual).to(beTrue()); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is nil, false, or an object with a boolean value of false:</span> <span class="pl-en">expect</span>(actual).to(beFalsy()); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is only false (not nil or an object conforming to Boolean false):</span> <span class="pl-en">expect</span>(actual).to(beFalse()); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is nil:</span> <span class="pl-en">expect</span>(actual).to(beNil());</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Swift Assertions</h2><a id="user-content-swift-assertions" class="anchor" aria-label="Permalink: Swift Assertions" href="#swift-assertions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If you're using Swift, you can use the <code>throwAssertion</code> matcher to check if an assertion is thrown (e.g. <code>fatalError()</code>). This is made possible by <a href="https://github.com/mattgallagher">@mattgallagher</a>'s <a href="https://github.com/mattgallagher/CwlPreconditionTesting">CwlPreconditionTesting</a> library.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'somethingThatThrows()' throws an assertion, // such as by calling 'fatalError()' or if a precondition fails: expect { try somethingThatThrows() }.to(throwAssertion()) expect { () -> Void in fatalError() }.to(throwAssertion()) expect { precondition(false) }.to(throwAssertion()) // Passes if throwing an NSError is not equal to throwing an assertion: expect { throw NSError(domain: "test", code: 0, userInfo: nil) }.toNot(throwAssertion()) // Passes if the code after the precondition check is not run: var reachedPoint1 = false var reachedPoint2 = false expect { reachedPoint1 = true precondition(false, "condition message") reachedPoint2 = true }.to(throwAssertion()) expect(reachedPoint1) == true expect(reachedPoint2) == false"><pre>// Swift // Passes if 'somethingThatThrows()' throws an assertion, // such as by calling 'fatalError()' or if a precondition fails: <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">somethingThatThrows</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwAssertion</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Void</span> <span class="pl-k">in</span> <span class="pl-en">fatalError</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwAssertion</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-en">precondition</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwAssertion</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if throwing an NSError is not equal to throwing an assertion: <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-k">throw</span> <span class="pl-en">NSError</span><span class="pl-kos">(</span>domain<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">test</span><span class="pl-s">"</span><span class="pl-kos">,</span> code<span class="pl-kos">:</span> <span class="pl-c1">0</span><span class="pl-kos">,</span> userInfo<span class="pl-kos">:</span> <span class="pl-smi">nil</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">throwAssertion</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if the code after the precondition check is not run: <span class="pl-k">var</span> <span class="pl-s1">reachedPoint1</span> <span class="pl-c1">=</span> <span class="pl-c1">false</span> <span class="pl-k">var</span> <span class="pl-s1">reachedPoint2</span> <span class="pl-c1">=</span> <span class="pl-c1">false</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> reachedPoint1 <span class="pl-c1">=</span> <span class="pl-c1">true</span> <span class="pl-en">precondition</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">condition message</span><span class="pl-s">"</span><span class="pl-kos">)</span> reachedPoint2 <span class="pl-c1">=</span> <span class="pl-c1">true</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwAssertion</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>reachedPoint1<span class="pl-kos">)</span> <span class="pl-c1">==</span> <span class="pl-c1">true</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>reachedPoint2<span class="pl-kos">)</span> <span class="pl-c1">==</span> <span class="pl-c1">false</span></pre></div> <p dir="auto">Notes:</p> <ul dir="auto"> <li>This feature is only available in Swift.</li> <li>The tvOS simulator is supported, but using a different mechanism, requiring you to turn off the <code>Debug executable</code> scheme setting for your tvOS scheme's Test configuration.</li> </ul> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Swift Error Handling</h2><a id="user-content-swift-error-handling" class="anchor" aria-label="Permalink: Swift Error Handling" href="#swift-error-handling"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">You can use the <code>throwError</code> matcher to check if an error is thrown.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'somethingThatThrows()' throws an 'Error': expect { try somethingThatThrows() }.to(throwError()) // Passes if 'somethingThatThrows()' throws an error within a particular domain: expect { try somethingThatThrows() }.to(throwError { (error: Error) in expect(error._domain).to(equal(NSCocoaErrorDomain)) }) // Passes if 'somethingThatThrows()' throws a particular error enum case: expect { try somethingThatThrows() }.to(throwError(NSCocoaError.PropertyListReadCorruptError)) // Passes if 'somethingThatThrows()' throws an error of a particular type: expect { try somethingThatThrows() }.to(throwError(errorType: NimbleError.self))"><pre>// Swift // Passes if 'somethingThatThrows()' throws an 'Error': <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">somethingThatThrows</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwError</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'somethingThatThrows()' throws an error within a particular domain: <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">somethingThatThrows</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwError</span> <span class="pl-kos">{</span> <span class="pl-kos">(</span>error<span class="pl-kos">:</span> <span class="pl-smi">Error</span><span class="pl-kos">)</span> <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>error<span class="pl-kos">.</span>_domain<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span>NSCocoaErrorDomain<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">)</span> // Passes if 'somethingThatThrows()' throws a particular error enum case: <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">somethingThatThrows</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwError</span><span class="pl-kos">(</span><span class="pl-smi">NSCocoaError</span><span class="pl-kos">.</span>PropertyListReadCorruptError<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'somethingThatThrows()' throws an error of a particular type: <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">somethingThatThrows</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">throwError</span><span class="pl-kos">(</span>errorType<span class="pl-kos">:</span> <span class="pl-smi">NimbleError</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">When working directly with <code>Error</code> values, using the <code>matchError</code> matcher allows you to perform certain checks on the error itself without having to explicitly cast the error.</p> <p dir="auto">The <code>matchError</code> matcher allows you to check whether or not the error:</p> <ul dir="auto"> <li>is the same <em>type</em> of error you are expecting.</li> <li>represents a particular error value that you are expecting.</li> </ul> <p dir="auto">This can be useful when using <code>Result</code> or <code>Promise</code> types, for example.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift let actual: Error = ... // Passes if 'actual' represents any error value from the NimbleErrorEnum type: expect(actual).to(matchError(NimbleErrorEnum.self)) // Passes if 'actual' represents the case 'timeout' from the NimbleErrorEnum type: expect(actual).to(matchError(NimbleErrorEnum.timeout)) // Passes if 'actual' contains an NSError equal to the one provided: expect(actual).to(matchError(NSError(domain: "err", code: 123, userInfo: nil)))"><pre>// Swift <span class="pl-k">let</span> <span class="pl-s1">actual</span><span class="pl-kos">:</span> <span class="pl-smi">Error</span> <span class="pl-c1">=</span> <span class="pl-c1">...</span> // Passes if 'actual' represents any error value from the NimbleErrorEnum type: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">matchError</span><span class="pl-kos">(</span><span class="pl-smi">NimbleErrorEnum</span><span class="pl-kos">.</span>self<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' represents the case 'timeout' from the NimbleErrorEnum type: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">matchError</span><span class="pl-kos">(</span><span class="pl-smi">NimbleErrorEnum</span><span class="pl-kos">.</span>timeout<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' contains an NSError equal to the one provided: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">matchError</span><span class="pl-kos">(</span><span class="pl-en">NSError</span><span class="pl-kos">(</span>domain<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">err</span><span class="pl-s">"</span><span class="pl-kos">,</span> code<span class="pl-kos">:</span> <span class="pl-c1">123</span><span class="pl-kos">,</span> userInfo<span class="pl-kos">:</span> <span class="pl-smi">nil</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Note: This feature is only available in Swift.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Exceptions</h2><a id="user-content-exceptions" class="anchor" aria-label="Permalink: Exceptions" href="#exceptions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'actual', when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if 'actual' raises an exception with the given name: expect(actual).to(raiseException(named: name)) // Passes if 'actual' raises an exception with the given name and reason: expect(actual).to(raiseException(named: name, reason: reason)) // Passes if 'actual' raises an exception which passes expectations defined in the given closure: // (in this case, if the exception's name begins with "a r") expect { exception.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(beginWith("a r")) })"><pre>// Swift // Passes if 'actual', when evaluated, raises an exception: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' raises an exception with the given name: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span>named<span class="pl-kos">:</span> name<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' raises an exception with the given name and reason: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span><span class="pl-kos">(</span>named<span class="pl-kos">:</span> name<span class="pl-kos">,</span> reason<span class="pl-kos">:</span> reason<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' raises an exception which passes expectations defined in the given closure: // (in this case, if the exception's name begins with "a r") <span class="pl-en">expect</span> <span class="pl-kos">{</span> exception<span class="pl-kos">.</span><span class="pl-en">raise</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">raiseException</span> <span class="pl-kos">{</span> <span class="pl-kos">(</span>exception<span class="pl-kos">:</span> <span class="pl-smi">NSException</span><span class="pl-kos">)</span> <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>exception<span class="pl-kos">.</span>name<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beginWith</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">a r</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual', when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if 'actual' raises an exception with the given name expect(actual).to(raiseException().named(name)) // Passes if 'actual' raises an exception with the given name and reason: expect(actual).to(raiseException().named(name).reason(reason)) // Passes if 'actual' raises an exception and it passes expectations defined in the given block: // (in this case, if name begins with "a r") expect(actual).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(@"a r")); }));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual', when evaluated, raises an exception:</span> <span class="pl-en">expect</span>(actual).to(raiseException()) <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' raises an exception with the given name</span> expect(actual).to(raiseException().named(name)) <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' raises an exception with the given name and reason:</span> expect(actual).to(raiseException().named(name).reason(reason)) <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' raises an exception and it passes expectations defined in the given block:</span> <span class="pl-c"><span class="pl-c">//</span> (in this case, if name begins with "a r")</span> expect(actual).to(raiseException().satisfyingBlock(^(<span class="pl-c1">NSException</span> *<span class="pl-c1">exception</span>) { <span class="pl-c1">expect</span>(<span class="pl-c1">exception</span>.<span class="pl-smi">name</span>).<span class="pl-c1">to</span>(<span class="pl-c1">beginWith</span>(<span class="pl-s"><span class="pl-pds">@"</span>a r<span class="pl-pds">"</span></span>)); }));</pre></div> <p dir="auto">Note: Swift currently doesn't have exceptions (see <a href="https://github.com/Quick/Nimble/issues/220#issuecomment-172667064" data-hovercard-type="issue" data-hovercard-url="/Quick/Nimble/issues/220/hovercard">#220</a>). Only Objective-C code can raise exceptions that Nimble will catch.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Collection Membership</h2><a id="user-content-collection-membership" class="anchor" aria-label="Permalink: Collection Membership" href="#collection-membership"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if all of the expected values are members of 'actual': expect(actual).to(contain(expected...)) // Passes if 'actual' is empty (i.e. it contains no elements): expect(actual).to(beEmpty())"><pre>// Swift // Passes if all of the expected values are members of 'actual': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span>expected<span class="pl-c1">...</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' is empty (i.e. it contains no elements): <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beEmpty</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if expected is a member of 'actual': expect(actual).to(contain(expected)); // Passes if 'actual' is empty (i.e. it contains no elements): expect(actual).to(beEmpty());"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if expected is a member of 'actual':</span> <span class="pl-en">expect</span>(actual).to(contain(expected)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' is empty (i.e. it contains no elements):</span> <span class="pl-en">expect</span>(actual).to(beEmpty());</pre></div> <blockquote> <p dir="auto">In Swift <code>contain</code> takes any number of arguments. The expectation passes if all of them are members of the collection. In Objective-C, <code>contain</code> only takes one argument <a href="https://github.com/Quick/Nimble/issues/27" data-hovercard-type="issue" data-hovercard-url="/Quick/Nimble/issues/27/hovercard">for now</a>.</p> </blockquote> <p dir="auto">For example, to assert that a list of sea creature names contains "dolphin" and "starfish":</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift expect(["whale", "dolphin", "starfish"]).to(contain("dolphin", "starfish"))"><pre>// Swift <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-s">"</span><span class="pl-s">whale</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">dolphin</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">starfish</span><span class="pl-s">"</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">dolphin</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">starfish</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"dolphin")); expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"starfish"));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(@[<span class="pl-s"><span class="pl-pds">@"</span>whale<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">@"</span>dolphin<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">@"</span>starfish<span class="pl-pds">"</span></span>]).to(contain(<span class="pl-s"><span class="pl-pds">@"</span>dolphin<span class="pl-pds">"</span></span>)); <span class="pl-en">expect</span>(@[<span class="pl-s"><span class="pl-pds">@"</span>whale<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">@"</span>dolphin<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">@"</span>starfish<span class="pl-pds">"</span></span>]).to(contain(<span class="pl-s"><span class="pl-pds">@"</span>starfish<span class="pl-pds">"</span></span>));</pre></div> <blockquote> <p dir="auto"><code>contain</code> and <code>beEmpty</code> expect collections to be instances of <code>NSArray</code>, <code>NSSet</code>, or a Swift collection composed of <code>Equatable</code> elements.</p> </blockquote> <p dir="auto">To test whether a set of elements is present at the beginning or end of an ordered collection, use <code>beginWith</code> and <code>endWith</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if the elements in expected appear at the beginning of 'actual': expect(actual).to(beginWith(expected...)) // Passes if the the elements in expected come at the end of 'actual': expect(actual).to(endWith(expected...))"><pre>// Swift // Passes if the elements in expected appear at the beginning of 'actual': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beginWith</span><span class="pl-kos">(</span>expected<span class="pl-c1">...</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if the the elements in expected come at the end of 'actual': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">endWith</span><span class="pl-kos">(</span>expected<span class="pl-c1">...</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if the elements in expected appear at the beginning of 'actual': expect(actual).to(beginWith(expected)); // Passes if the the elements in expected come at the end of 'actual': expect(actual).to(endWith(expected));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if the elements in expected appear at the beginning of 'actual':</span> <span class="pl-en">expect</span>(actual).to(beginWith(expected)); <span class="pl-c"><span class="pl-c">//</span> Passes if the the elements in expected come at the end of 'actual':</span> <span class="pl-en">expect</span>(actual).to(endWith(expected));</pre></div> <blockquote> <p dir="auto"><code>beginWith</code> and <code>endWith</code> expect collections to be instances of <code>NSArray</code>, or ordered Swift collections composed of <code>Equatable</code> elements.</p> </blockquote> <p dir="auto">Like <code>contain</code>, in Objective-C <code>beginWith</code> and <code>endWith</code> only support a single argument <a href="https://github.com/Quick/Nimble/issues/27" data-hovercard-type="issue" data-hovercard-url="/Quick/Nimble/issues/27/hovercard">for now</a>.</p> <p dir="auto">For code that returns collections of complex objects without a strict ordering, there is the <code>containElementSatisfying</code> matcher:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift struct Turtle { let color: String } let turtles: [Turtle] = functionThatReturnsSomeTurtlesInAnyOrder() // This set of matchers passes regardless of whether the array is // [{color: "blue"}, {color: "green"}] or [{color: "green"}, {color: "blue"}]: expect(turtles).to(containElementSatisfying({ turtle in return turtle.color == "green" })) expect(turtles).to(containElementSatisfying({ turtle in return turtle.color == "blue" }, "that is a turtle with color 'blue'")) // The second matcher will incorporate the provided string in the error message // should it fail"><pre>// Swift <span class="pl-k">struct</span> <span class="pl-smi">Turtle</span> <span class="pl-kos">{</span> <span class="pl-k">let</span> <span class="pl-s1"><span class="pl-c1">color</span></span><span class="pl-kos">:</span> <span class="pl-smi">String</span> <span class="pl-kos">}</span> <span class="pl-k">let</span> <span class="pl-s1">turtles</span><span class="pl-kos">:</span> <span class="pl-kos">[</span><span class="pl-smi">Turtle</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">functionThatReturnsSomeTurtlesInAnyOrder</span><span class="pl-kos">(</span><span class="pl-kos">)</span> // This set of matchers passes regardless of whether the array is // [{color: "blue"}, {color: "green"}] or [{color: "green"}, {color: "blue"}]: <span class="pl-en">expect</span><span class="pl-kos">(</span>turtles<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">containElementSatisfying</span><span class="pl-kos">(</span><span class="pl-kos">{</span> turtle <span class="pl-k">in</span> <span class="pl-k">return</span> turtle<span class="pl-kos">.</span>color <span class="pl-c1">==</span> <span class="pl-s">"</span><span class="pl-s">green</span><span class="pl-s">"</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>turtles<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">containElementSatisfying</span><span class="pl-kos">(</span><span class="pl-kos">{</span> turtle <span class="pl-k">in</span> <span class="pl-k">return</span> turtle<span class="pl-kos">.</span>color <span class="pl-c1">==</span> <span class="pl-s">"</span><span class="pl-s">blue</span><span class="pl-s">"</span> <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">that is a turtle with color 'blue'</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // The second matcher will incorporate the provided string in the error message // should it fail</pre></div> <p dir="auto">Note: in Swift, <code>containElementSatisfying</code> also has a variant that takes in an async function.</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C @interface Turtle : NSObject @property (nonatomic, readonly, nonnull) NSString *color; @end @implementation Turtle @end NSArray<Turtle *> * __nonnull turtles = functionThatReturnsSomeTurtlesInAnyOrder(); // This set of matchers passes regardless of whether the array is // [{color: "blue"}, {color: "green"}] or [{color: "green"}, {color: "blue"}]: expect(turtles).to(containElementSatisfying(^BOOL(id __nonnull object) { return [[turtle color] isEqualToString:@"green"]; })); expect(turtles).to(containElementSatisfying(^BOOL(id __nonnull object) { return [[turtle color] isEqualToString:@"blue"]; }));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-k">@interface</span> <span class="pl-en">Turtle</span> : <span class="pl-e">NSObject</span> <span class="pl-k">@property</span> (<span class="pl-k">nonatomic</span>, <span class="pl-k">readonly</span>, <span class="pl-k">nonnull</span>) <span class="pl-c1">NSString</span> *color; <span class="pl-k">@end</span> <span class="pl-k">@implementation</span> <span class="pl-en">Turtle</span> <span class="pl-k">@end</span> <span class="pl-c1">NSArray</span><Turtle *> * __nonnull turtles = functionThatReturnsSomeTurtlesInAnyOrder(); <span class="pl-c"><span class="pl-c">//</span> This set of matchers passes regardless of whether the array is </span> <span class="pl-c"><span class="pl-c">//</span> [{color: "blue"}, {color: "green"}] or [{color: "green"}, {color: "blue"}]:</span> <span class="pl-en">expect</span>(turtles).to(containElementSatisfying(^<span class="pl-c1">BOOL</span>(<span class="pl-c1">id</span> __nonnull object) { <span class="pl-k">return</span> [[turtle <span class="pl-c1">color</span>] <span class="pl-c1">isEqualToString:</span><span class="pl-s"><span class="pl-pds">@"</span>green<span class="pl-pds">"</span></span>]; })); <span class="pl-en">expect</span>(turtles).to(containElementSatisfying(^<span class="pl-c1">BOOL</span>(<span class="pl-c1">id</span> __nonnull object) { <span class="pl-k">return</span> [[turtle <span class="pl-c1">color</span>] <span class="pl-c1">isEqualToString:</span><span class="pl-s"><span class="pl-pds">@"</span>blue<span class="pl-pds">"</span></span>]; }));</pre></div> <p dir="auto">For asserting on if the given <code>Comparable</code> value is inside of a <code>Range</code>, use the <code>beWithin</code> matcher.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 5 is within the range 1 through 10, inclusive expect(5).to(beWithin(1...10)) // Passes if 5 is not within the range 2 through 4. expect(5).toNot(beWithin(2..<5))"><pre>// Swift // Passes if 5 is within the range 1 through 10, inclusive <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beWithin</span><span class="pl-kos">(</span><span class="pl-c1">1</span><span class="pl-c1">...</span><span class="pl-c1">10</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 5 is not within the range 2 through 4. <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toNot</span><span class="pl-kos">(</span><span class="pl-en">beWithin</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-c1">..<</span><span class="pl-c1">5</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Strings</h2><a id="user-content-strings" class="anchor" aria-label="Permalink: Strings" href="#strings"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'actual' contains 'substring': expect(actual).to(contain(substring)) // Passes if 'actual' begins with 'prefix': expect(actual).to(beginWith(prefix)) // Passes if 'actual' ends with 'suffix': expect(actual).to(endWith(suffix)) // Passes if 'actual' represents the empty string, "": expect(actual).to(beEmpty()) // Passes if 'actual' matches the regular expression defined in 'expected': expect(actual).to(match(expected))"><pre>// Swift // Passes if 'actual' contains 'substring': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">contain</span><span class="pl-kos">(</span>substring<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' begins with 'prefix': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beginWith</span><span class="pl-kos">(</span>prefix<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' ends with 'suffix': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">endWith</span><span class="pl-kos">(</span>suffix<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' represents the empty string, "": <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beEmpty</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' matches the regular expression defined in 'expected': <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">match</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual' contains 'substring': expect(actual).to(contain(expected)); // Passes if 'actual' begins with 'prefix': expect(actual).to(beginWith(prefix)); // Passes if 'actual' ends with 'suffix': expect(actual).to(endWith(suffix)); // Passes if 'actual' represents the empty string, "": expect(actual).to(beEmpty()); // Passes if 'actual' matches the regular expression defined in 'expected': expect(actual).to(match(expected))"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' contains 'substring':</span> <span class="pl-en">expect</span>(actual).to(contain(expected)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' begins with 'prefix':</span> <span class="pl-en">expect</span>(actual).to(beginWith(prefix)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' ends with 'suffix':</span> <span class="pl-en">expect</span>(actual).to(endWith(suffix)); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' represents the empty string, "":</span> <span class="pl-en">expect</span>(actual).to(beEmpty()); <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' matches the regular expression defined in 'expected':</span> <span class="pl-en">expect</span>(actual).to(match(expected))</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Collection Elements</h2><a id="user-content-collection-elements" class="anchor" aria-label="Permalink: Collection Elements" href="#collection-elements"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble provides a means to check that all elements of a collection pass a given expectation.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Swift</h3><a id="user-content-swift" class="anchor" aria-label="Permalink: Swift" href="#swift"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In Swift, the collection must be an instance of a type conforming to <code>Sequence</code>.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Providing a custom function: expect([1, 2, 3, 4]).to(allPass { $0 < 5 }) // Composing the expectation with another matcher: expect([1, 2, 3, 4]).to(allPass(beLessThan(5)))"><pre>// Swift // Providing a custom function: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">,</span> <span class="pl-c1">4</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">allPass</span> <span class="pl-kos">{</span> $0 <span class="pl-c1"><</span> <span class="pl-c1">5</span> <span class="pl-kos">}</span><span class="pl-kos">)</span> // Composing the expectation with another matcher: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">,</span> <span class="pl-c1">4</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">allPass</span><span class="pl-kos">(</span><span class="pl-en">beLessThan</span><span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">There are also variants of <code>allPass</code> that check against async matchers, and that take in async functions:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Providing a custom function: expect([1, 2, 3, 4]).to(allPass { await asyncFunctionReturningBool($0) }) // Composing the expectation with another matcher: expect([1, 2, 3, 4]).to(allPass(someAsyncMatcher()))"><pre>// Swift // Providing a custom function: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">,</span> <span class="pl-c1">4</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">allPass</span> <span class="pl-kos">{</span> <span class="pl-k">await</span> <span class="pl-en">asyncFunctionReturningBool</span><span class="pl-kos">(</span>$0<span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">)</span> // Composing the expectation with another matcher: <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-c1">1</span><span class="pl-kos">,</span> <span class="pl-c1">2</span><span class="pl-kos">,</span> <span class="pl-c1">3</span><span class="pl-kos">,</span> <span class="pl-c1">4</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">allPass</span><span class="pl-kos">(</span><span class="pl-en">someAsyncMatcher</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Objective-C</h3><a id="user-content-objective-c" class="anchor" aria-label="Permalink: Objective-C" href="#objective-c"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In Objective-C, the collection must be an instance of a type which implements the <code>NSFastEnumeration</code> protocol, and whose elements are instances of a type which subclasses <code>NSObject</code>.</p> <p dir="auto">Additionally, unlike in Swift, there is no override to specify a custom matcher function.</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(@[@1, @2, @3, @4]).to(allPass(beLessThan(@5)));"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(@[@<span class="pl-c1">1</span>, @<span class="pl-c1">2</span>, @<span class="pl-c1">3</span>, @<span class="pl-c1">4</span>]).to(allPass(beLessThan(@<span class="pl-c1">5</span>)));</pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Collection Count</h2><a id="user-content-collection-count" class="anchor" aria-label="Permalink: Collection Count" href="#collection-count"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // Passes if 'actual' contains the 'expected' number of elements: expect(actual).to(haveCount(expected)) // Passes if 'actual' does _not_ contain the 'expected' number of elements: expect(actual).notTo(haveCount(expected))"><pre>// Swift // Passes if 'actual' contains the 'expected' number of elements: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">haveCount</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if 'actual' does _not_ contain the 'expected' number of elements: <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">notTo</span><span class="pl-kos">(</span><span class="pl-en">haveCount</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // Passes if 'actual' contains the 'expected' number of elements: expect(actual).to(haveCount(expected)) // Passes if 'actual' does _not_ contain the 'expected' number of elements: expect(actual).notTo(haveCount(expected))"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' contains the 'expected' number of elements:</span> <span class="pl-en">expect</span>(actual).to(haveCount(expected)) <span class="pl-c"><span class="pl-c">//</span> Passes if 'actual' does _not_ contain the 'expected' number of elements:</span> expect(actual).notTo(haveCount(expected))</pre></div> <p dir="auto">For Swift, the actual value must be an instance of a type conforming to <code>Collection</code>. For example, instances of <code>Array</code>, <code>Dictionary</code>, or <code>Set</code>.</p> <p dir="auto">For Objective-C, the actual value must be one of the following classes, or their subclasses:</p> <ul dir="auto"> <li><code>NSArray</code>,</li> <li><code>NSDictionary</code>,</li> <li><code>NSSet</code>, or</li> <li><code>NSHashTable</code>.</li> </ul> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Notifications</h2><a id="user-content-notifications" class="anchor" aria-label="Permalink: Notifications" href="#notifications"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift let testNotification = Notification(name: Notification.Name("Foo"), object: nil) // Passes if the closure in expect { ... } posts a notification to the default // notification center. expect { NotificationCenter.default.post(testNotification) }.to(postNotifications(equal([testNotification]))) // Passes if the closure in expect { ... } posts a notification to a given // notification center let notificationCenter = NotificationCenter() expect { notificationCenter.post(testNotification) }.to(postNotifications(equal([testNotification]), from: notificationCenter)) // Passes if the closure in expect { ... } posts a notification with the provided names to a given // notification center. Make sure to use this when running tests on Catalina, // using DistributedNotificationCenter as there is currently no way // of observing notifications without providing specific names. let distributedNotificationCenter = DistributedNotificationCenter() expect { distributedNotificationCenter.post(testNotification) }.toEventually(postDistributedNotifications(equal([testNotification]), from: distributedNotificationCenter, names: [testNotification.name]))"><pre>// Swift <span class="pl-k">let</span> <span class="pl-s1">testNotification</span> <span class="pl-c1">=</span> <span class="pl-en">Notification</span><span class="pl-kos">(</span>name<span class="pl-kos">:</span> <span class="pl-smi">Notification</span><span class="pl-kos">.</span><span class="pl-en">Name</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Foo</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">,</span> object<span class="pl-kos">:</span> <span class="pl-smi">nil</span><span class="pl-kos">)</span> // Passes if the closure in expect { ... } posts a notification to the default // notification center. <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-smi">NotificationCenter</span><span class="pl-kos">.</span>default<span class="pl-kos">.</span><span class="pl-en">post</span><span class="pl-kos">(</span>testNotification<span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">postNotifications</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-kos">[</span>testNotification<span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if the closure in expect { ... } posts a notification to a given // notification center <span class="pl-k">let</span> <span class="pl-s1">notificationCenter</span> <span class="pl-c1">=</span> <span class="pl-en">NotificationCenter</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> notificationCenter<span class="pl-kos">.</span><span class="pl-en">post</span><span class="pl-kos">(</span>testNotification<span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">postNotifications</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-kos">[</span>testNotification<span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">,</span> from<span class="pl-kos">:</span> notificationCenter<span class="pl-kos">)</span><span class="pl-kos">)</span> // Passes if the closure in expect { ... } posts a notification with the provided names to a given // notification center. Make sure to use this when running tests on Catalina, // using DistributedNotificationCenter as there is currently no way // of observing notifications without providing specific names. <span class="pl-k">let</span> <span class="pl-s1">distributedNotificationCenter</span> <span class="pl-c1">=</span> <span class="pl-en">DistributedNotificationCenter</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-en">expect</span> <span class="pl-kos">{</span> distributedNotificationCenter<span class="pl-kos">.</span><span class="pl-en">post</span><span class="pl-kos">(</span>testNotification<span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">toEventually</span><span class="pl-kos">(</span><span class="pl-en">postDistributedNotifications</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-kos">[</span>testNotification<span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">,</span> from<span class="pl-kos">:</span> distributedNotificationCenter<span class="pl-kos">,</span> names<span class="pl-kos">:</span> <span class="pl-kos">[</span>testNotification<span class="pl-kos">.</span>name<span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <blockquote> <p dir="auto">This matcher is only available in Swift.</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Result</h2><a id="user-content-result" class="anchor" aria-label="Permalink: Result" href="#result"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift let aResult: Result<String, Error> = .success("Hooray") // passes if result is .success expect(aResult).to(beSuccess()) // passes if result value is .success and validates Success value expect(aResult).to(beSuccess { value in expect(value).to(equal("Hooray")) }) enum AnError: Error { case somethingHappened } let otherResult: Result<String, AnError> = .failure(.somethingHappened) // passes if result is .failure expect(otherResult).to(beFailure()) // passes if result value is .failure and validates error expect(otherResult).to(beFailure { error in expect(error).to(matchError(AnError.somethingHappened)) }) "><pre>// Swift <span class="pl-k">let</span> <span class="pl-s1">aResult</span><span class="pl-kos">:</span> <span class="pl-smi">Result</span><span class="pl-c1"><</span><span class="pl-smi">String</span><span class="pl-kos">,</span> <span class="pl-smi">Error</span><span class="pl-c1">></span> <span class="pl-c1">=</span> <span class="pl-kos">.</span>success<span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Hooray</span><span class="pl-s">"</span><span class="pl-kos">)</span> // passes if result is .success <span class="pl-en">expect</span><span class="pl-kos">(</span>aResult<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beSuccess</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // passes if result value is .success and validates Success value <span class="pl-en">expect</span><span class="pl-kos">(</span>aResult<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beSuccess</span> <span class="pl-kos">{</span> value <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>value<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Hooray</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">)</span> <span class="pl-k">enum</span> <span class="pl-smi">AnError</span><span class="pl-kos">:</span> <span class="pl-smi">Error</span> <span class="pl-kos">{</span> <span class="pl-k">case</span> somethingHappened <span class="pl-kos">}</span> <span class="pl-k">let</span> <span class="pl-s1">otherResult</span><span class="pl-kos">:</span> <span class="pl-smi">Result</span><span class="pl-c1"><</span><span class="pl-smi">String</span><span class="pl-kos">,</span> <span class="pl-smi">AnError</span><span class="pl-c1">></span> <span class="pl-c1">=</span> <span class="pl-kos">.</span>failure<span class="pl-kos">(</span><span class="pl-kos">.</span>somethingHappened<span class="pl-kos">)</span> // passes if result is .failure <span class="pl-en">expect</span><span class="pl-kos">(</span>otherResult<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beFailure</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // passes if result value is .failure and validates error <span class="pl-en">expect</span><span class="pl-kos">(</span>otherResult<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beFailure</span> <span class="pl-kos">{</span> error <span class="pl-k">in</span> <span class="pl-en">expect</span><span class="pl-kos">(</span>error<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">matchError</span><span class="pl-kos">(</span><span class="pl-smi">AnError</span><span class="pl-kos">.</span>somethingHappened<span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span><span class="pl-kos">)</span> </pre></div> <blockquote> <p dir="auto">This matcher is only available in Swift.</p> </blockquote> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Matching a value to any of a group of matchers</h2><a id="user-content-matching-a-value-to-any-of-a-group-of-matchers" class="anchor" aria-label="Permalink: Matching a value to any of a group of matchers" href="#matching-a-value-to-any-of-a-group-of-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // passes if actual is either less than 10 or greater than 20 expect(actual).to(satisfyAnyOf(beLessThan(10), beGreaterThan(20))) // can include any number of matchers -- the following will pass // **be careful** -- too many matchers can be the sign of an unfocused test expect(6).to(satisfyAnyOf(equal(2), equal(3), equal(4), equal(5), equal(6), equal(7))) // in Swift you also have the option to use the || operator to achieve a similar function expect(82).to(beLessThan(50) || beGreaterThan(80))"><pre>// Swift // passes if actual is either less than 10 or greater than 20 <span class="pl-en">expect</span><span class="pl-kos">(</span>actual<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">satisfyAnyOf</span><span class="pl-kos">(</span><span class="pl-en">beLessThan</span><span class="pl-kos">(</span><span class="pl-c1">10</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">beGreaterThan</span><span class="pl-kos">(</span><span class="pl-c1">20</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // can include any number of matchers -- the following will pass // **be careful** -- too many matchers can be the sign of an unfocused test <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">6</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">satisfyAnyOf</span><span class="pl-kos">(</span><span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">2</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">3</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">4</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">5</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">6</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-en">equal</span><span class="pl-kos">(</span><span class="pl-c1">7</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // in Swift you also have the option to use the || operator to achieve a similar function <span class="pl-en">expect</span><span class="pl-kos">(</span><span class="pl-c1">82</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">beLessThan</span><span class="pl-kos">(</span><span class="pl-c1">50</span><span class="pl-kos">)</span> || <span class="pl-en">beGreaterThan</span><span class="pl-kos">(</span><span class="pl-c1">80</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">Note: In swift, you can mix and match synchronous and asynchronous matchers using by <code>satisfyAnyOf</code>/<code>||</code>.</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C // passes if actual is either less than 10 or greater than 20 expect(actual).to(satisfyAnyOf(beLessThan(@10), beGreaterThan(@20))) // can include any number of matchers -- the following will pass // **be careful** -- too many matchers can be the sign of an unfocused test expect(@6).to(satisfyAnyOf(equal(@2), equal(@3), equal(@4), equal(@5), equal(@6), equal(@7)))"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-c"><span class="pl-c">//</span> passes if actual is either less than 10 or greater than 20</span> <span class="pl-en">expect</span>(actual).to(satisfyAnyOf(beLessThan(@<span class="pl-c1">10</span>), beGreaterThan(@<span class="pl-c1">20</span>))) <span class="pl-c"><span class="pl-c">//</span> can include any number of matchers -- the following will pass</span> <span class="pl-c"><span class="pl-c">//</span> **be careful** -- too many matchers can be the sign of an unfocused test</span> expect(@<span class="pl-c1">6</span>).to(satisfyAnyOf(equal(@<span class="pl-c1">2</span>), equal(@<span class="pl-c1">3</span>), equal(@<span class="pl-c1">4</span>), equal(@<span class="pl-c1">5</span>), equal(@<span class="pl-c1">6</span>), equal(@<span class="pl-c1">7</span>)))</pre></div> <p dir="auto">Note: This matcher allows you to chain any number of matchers together. This provides flexibility, but if you find yourself chaining many matchers together in one test, consider whether you could instead refactor that single test into multiple, more precisely focused tests for better coverage.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Custom Validation</h2><a id="user-content-custom-validation" class="anchor" aria-label="Permalink: Custom Validation" href="#custom-validation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift // passes if .succeeded is returned from the closure expect { guard case .enumCaseWithAssociatedValueThatIDontCareAbout = actual else { return .failed(reason: "wrong enum case") } return .succeeded }.to(succeed()) // passes if .failed is returned from the closure expect { guard case .enumCaseWithAssociatedValueThatIDontCareAbout = actual else { return .failed(reason: "wrong enum case") } return .succeeded }.notTo(succeed())"><pre>// Swift // passes if .succeeded is returned from the closure <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-k">guard</span> case <span class="pl-kos">.</span>enumCaseWithAssociatedValueThatIDontCareAbout <span class="pl-c1">=</span> actual <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-kos">.</span>failed<span class="pl-kos">(</span>reason<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">wrong enum case</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-kos">.</span>succeeded <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">to</span><span class="pl-kos">(</span><span class="pl-en">succeed</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> // passes if .failed is returned from the closure <span class="pl-en">expect</span> <span class="pl-kos">{</span> <span class="pl-k">guard</span> case <span class="pl-kos">.</span>enumCaseWithAssociatedValueThatIDontCareAbout <span class="pl-c1">=</span> actual <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-kos">.</span>failed<span class="pl-kos">(</span>reason<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">wrong enum case</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-kos">.</span>succeeded <span class="pl-kos">}</span><span class="pl-kos">.</span><span class="pl-en">notTo</span><span class="pl-kos">(</span><span class="pl-en">succeed</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div> <p dir="auto">The <code>String</code> provided with <code>.failed()</code> is shown when the test fails.</p> <p dir="auto">When using <code>toEventually()</code> be careful not to make state changes or run process intensive code since this closure will be ran many times.</p> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Writing Your Own Matchers</h1><a id="user-content-writing-your-own-matchers" class="anchor" aria-label="Permalink: Writing Your Own Matchers" href="#writing-your-own-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">In Nimble, matchers are Swift functions that take an expected value and return a <code>Matcher</code> closure. Take <code>equal</code>, for example:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public func equal<T: Equatable>(expectedValue: T?) -> Matcher<T> { // Can be shortened to: // Matcher { actual in ... } // // But shown with types here for clarity. return Matcher { (actualExpression: Expression<T>) throws -> MatcherResult in let msg = ExpectationMessage.expectedActualValueTo("equal <\(expectedValue)>") if let actualValue = try actualExpression.evaluate() { return MatcherResult( bool: actualValue == expectedValue!, message: msg ) } else { return MatcherResult( status: .fail, message: msg.appendedBeNilHint() ) } } }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-en">func</span> equal<span class="pl-c1"><</span>T<span class="pl-kos">:</span> <span class="pl-smi">Equatable</span><span class="pl-c1">></span><span class="pl-kos">(</span>expectedValue<span class="pl-kos">:</span> <span class="pl-smi">T</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Matcher</span><span class="pl-c1"><</span><span class="pl-smi">T</span><span class="pl-c1">></span> <span class="pl-kos">{</span> // Can be shortened to: // Matcher { actual in ... } // // But shown with types here for clarity. <span class="pl-k">return</span> <span class="pl-en">Matcher</span> <span class="pl-kos">{</span> <span class="pl-kos">(</span>actualExpression<span class="pl-kos">:</span> <span class="pl-smi">Expression</span><span class="pl-c1"><</span><span class="pl-smi">T</span><span class="pl-c1">></span><span class="pl-kos">)</span> <span class="pl-k">throws</span> <span class="pl-c1">-></span> <span class="pl-smi">MatcherResult</span> <span class="pl-k">in</span> <span class="pl-k">let</span> <span class="pl-s1">msg</span> <span class="pl-c1">=</span> <span class="pl-smi">ExpectationMessage</span><span class="pl-kos">.</span><span class="pl-en">expectedActualValueTo</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">equal <</span><span class="pl-kos">\(</span>expectedValue<span class="pl-kos">)</span><span class="pl-s">></span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-k">if</span> <span class="pl-k">let</span> actualValue <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> actualExpression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span> bool<span class="pl-kos">:</span> actualValue <span class="pl-c1">==</span> expectedValue!<span class="pl-kos">,</span> message<span class="pl-kos">:</span> msg <span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span> status<span class="pl-kos">:</span> <span class="pl-kos">.</span>fail<span class="pl-kos">,</span> message<span class="pl-kos">:</span> msg<span class="pl-kos">.</span><span class="pl-en">appendedBeNilHint</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">The return value of a <code>Matcher</code> closure is a <code>MatcherResult</code> that indicates whether the actual value matches the expectation and what error message to display on failure.</p> <blockquote> <p dir="auto">The actual <code>equal</code> matcher function does not match when <code>expected</code> are nil; the example above has been edited for brevity.</p> </blockquote> <p dir="auto">Since matchers are just Swift functions, you can define them anywhere: at the top of your test file, in a file shared by all of your tests, or in an Xcode project you distribute to others.</p> <blockquote> <p dir="auto">If you write a matcher you think everyone can use, consider adding it to Nimble's built-in set of matchers by sending a pull request! Or distribute it yourself via GitHub.</p> </blockquote> <p dir="auto">For examples of how to write your own matchers, just check out the <a href="https://github.com/Quick/Nimble/tree/main/Sources/Nimble/Matchers"><code>Matchers</code> directory</a> to see how Nimble's built-in set of matchers are implemented. You can also check out the tips below.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">MatcherResult</h2><a id="user-content-matcherresult" class="anchor" aria-label="Permalink: MatcherResult" href="#matcherresult"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><code>MatcherResult</code> is the return struct that <code>Matcher</code> return to indicate success and failure. A <code>MatcherResult</code> is made up of two values: <code>MatcherStatus</code> and <code>ExpectationMessage</code>.</p> <p dir="auto">Instead of a boolean, <code>MatcherStatus</code> captures a trinary set of values:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public enum MatcherStatus { // The matcher "passes" with the given expression // eg - expect(1).to(equal(1)) case matches // The matcher "fails" with the given expression // eg - expect(1).toNot(equal(1)) case doesNotMatch // The matcher never "passes" with the given expression, even if negated // eg - expect(nil as Int?).toNot(equal(1)) case fail // ... }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-k">enum</span> <span class="pl-smi">MatcherStatus</span> <span class="pl-kos">{</span> // The matcher "passes" with the given expression // eg - expect(1).to(equal(1)) <span class="pl-k">case</span> matches // The matcher "fails" with the given expression // eg - expect(1).toNot(equal(1)) <span class="pl-k">case</span> doesNotMatch // The matcher never "passes" with the given expression, even if negated // eg - expect(nil as Int?).toNot(equal(1)) <span class="pl-k">case</span> fail // ... <span class="pl-kos">}</span></pre></div> <p dir="auto">Meanwhile, <code>ExpectationMessage</code> provides messaging semantics for error reporting.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public indirect enum ExpectationMessage { // Emits standard error message: // eg - "expected to <string>, got <actual>" case expectedActualValueTo(/* message: */ String) // Allows any free-form message // eg - "<string>" case fail(/* message: */ String) // ... }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-k">indirect</span> <span class="pl-k">enum</span> <span class="pl-smi">ExpectationMessage</span> <span class="pl-kos">{</span> // Emits standard error message: // eg - "expected to <string>, got <actual>" <span class="pl-k">case</span> expectedActualValueTo<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // Allows any free-form message // eg - "<string>" <span class="pl-k">case</span> fail<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // ... <span class="pl-kos">}</span></pre></div> <p dir="auto">Matchers should usually depend on either <code>.expectedActualValueTo(..)</code> or <code>.fail(..)</code> when reporting errors. Special cases can be used for the other enum cases.</p> <p dir="auto">Finally, if your Matcher utilizes other Matchers, you can utilize <code>.appended(details:)</code> and <code>.appended(message:)</code> methods to annotate an existing error with more details.</p> <p dir="auto">A common message to append is failing on nils. For that, <code>.appendedBeNilHint()</code> can be used.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Lazy Evaluation</h2><a id="user-content-lazy-evaluation" class="anchor" aria-label="Permalink: Lazy Evaluation" href="#lazy-evaluation"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><code>actualExpression</code> is a lazy, memoized closure around the value provided to the <code>expect</code> function. The expression can either be a closure or a value directly passed to <code>expect(...)</code>. In order to determine whether that value matches, custom matchers should call <code>actualExpression.evaluate()</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public func beNil<T>() -> Matcher<T> { // Matcher.simpleNilable(..) automatically generates ExpectationMessage for // us based on the string we provide to it. Also, the 'Nilable' postfix indicates // that this Matcher supports matching against nil actualExpressions, instead of // always resulting in a MatcherStatus.fail result -- which is true for // Matcher.simple(..) return Matcher.simpleNilable("be nil") { actualExpression in let actualValue = try actualExpression.evaluate() return MatcherStatus(bool: actualValue == nil) } }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-en">func</span> beNil<span class="pl-c1"><</span>T<span class="pl-c1">></span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Matcher</span><span class="pl-c1"><</span><span class="pl-smi">T</span><span class="pl-c1">></span> <span class="pl-kos">{</span> // Matcher.simpleNilable(..) automatically generates ExpectationMessage for // us based on the string we provide to it. Also, the 'Nilable' postfix indicates // that this Matcher supports matching against nil actualExpressions, instead of // always resulting in a MatcherStatus.fail result -- which is true for // Matcher.simple(..) <span class="pl-k">return</span> <span class="pl-smi">Matcher</span><span class="pl-kos">.</span><span class="pl-en">simpleNilable</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">be nil</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> actualExpression <span class="pl-k">in</span> <span class="pl-k">let</span> <span class="pl-s1">actualValue</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> actualExpression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">return</span> <span class="pl-en">MatcherStatus</span><span class="pl-kos">(</span>bool<span class="pl-kos">:</span> actualValue <span class="pl-c1">==</span> <span class="pl-smi">nil</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">In the above example, <code>actualExpression</code> is not <code>nil</code> -- it is a closure that returns a value. The value it returns, which is accessed via the <code>evaluate()</code> method, may be <code>nil</code>. If that value is <code>nil</code>, the <code>beNil</code> matcher function returns <code>true</code>, indicating that the expectation passed.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Type Checking via Swift Generics</h2><a id="user-content-type-checking-via-swift-generics" class="anchor" aria-label="Permalink: Type Checking via Swift Generics" href="#type-checking-via-swift-generics"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Using Swift's generics, matchers can constrain the type of the actual value passed to the <code>expect</code> function by modifying the return type.</p> <p dir="auto">For example, the following matcher, <code>haveDescription</code>, only accepts actual values that implement the <code>Printable</code> protocol. It checks their <code>description</code> against the one provided to the matcher function, and passes if they are the same:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public func haveDescription(description: String) -> Matcher<Printable?> { return Matcher.simple("have description") { actual in return MatcherStatus(bool: actual.evaluate().description == description) } }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-en">func</span> haveDescription<span class="pl-kos">(</span>description<span class="pl-kos">:</span> <span class="pl-smi">String</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Matcher</span><span class="pl-c1"><</span><span class="pl-smi">Printable</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-c1">></span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">Matcher</span><span class="pl-kos">.</span><span class="pl-en">simple</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">have description</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> actual <span class="pl-k">in</span> <span class="pl-k">return</span> <span class="pl-en">MatcherStatus</span><span class="pl-kos">(</span>bool<span class="pl-kos">:</span> actual<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span>description <span class="pl-c1">==</span> description<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Customizing Failure Messages</h2><a id="user-content-customizing-failure-messages" class="anchor" aria-label="Permalink: Customizing Failure Messages" href="#customizing-failure-messages"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">When using <code>Matcher.simple(..)</code> or <code>Matcher.simpleNilable(..)</code>, Nimble outputs the following failure message when an expectation fails:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// where `message` is the first string argument and // `actual` is the actual value received in `expect(..)` "expected to \(message), got <\(actual)>""><pre>// where `message` is the first string argument and // `actual` is the actual value received in `expect(..)` <span class="pl-s">"</span><span class="pl-s">expected to </span><span class="pl-kos">\(</span>message<span class="pl-kos">)</span><span class="pl-s">, got <</span><span class="pl-kos">\(</span>actual<span class="pl-kos">)</span><span class="pl-s">></span><span class="pl-s">"</span></pre></div> <p dir="auto">You can customize this message by modifying the way you create a <code>Matcher</code>.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Basic Customization</h3><a id="user-content-basic-customization" class="anchor" aria-label="Permalink: Basic Customization" href="#basic-customization"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">For slightly more complex error messaging, receive the created failure message with <code>Matcher.define(..)</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift public func equal<T: Equatable>(_ expectedValue: T?) -> Matcher<T> { return Matcher.define("equal <\(stringify(expectedValue))>") { actualExpression, msg in let actualValue = try actualExpression.evaluate() let matches = actualValue == expectedValue && expectedValue != nil if expectedValue == nil || actualValue == nil { if expectedValue == nil && actualValue != nil { return MatcherResult( status: .fail, message: msg.appendedBeNilHint() ) } return MatcherResult(status: .fail, message: msg) } return MatcherResult(bool: matches, message: msg) } }"><pre>// Swift <span class="pl-k">public</span> <span class="pl-en">func</span> equal<span class="pl-c1"><</span>T<span class="pl-kos">:</span> <span class="pl-smi">Equatable</span><span class="pl-c1">></span><span class="pl-kos">(</span>_ expectedValue<span class="pl-kos">:</span> <span class="pl-smi">T</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Matcher</span><span class="pl-c1"><</span><span class="pl-smi">T</span><span class="pl-c1">></span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">Matcher</span><span class="pl-kos">.</span><span class="pl-en">define</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">equal <</span><span class="pl-kos">\(</span><span class="pl-en">stringify</span><span class="pl-kos">(</span>expectedValue<span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-s">></span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> actualExpression<span class="pl-kos">,</span> msg <span class="pl-k">in</span> <span class="pl-k">let</span> <span class="pl-s1">actualValue</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> actualExpression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">matches</span> <span class="pl-c1">=</span> actualValue <span class="pl-c1">==</span> expectedValue && expectedValue <span class="pl-c1">!=</span> <span class="pl-smi">nil</span> <span class="pl-k">if</span> expectedValue <span class="pl-c1">==</span> <span class="pl-smi">nil</span> || actualValue <span class="pl-c1">==</span> <span class="pl-smi">nil</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> expectedValue <span class="pl-c1">==</span> <span class="pl-smi">nil</span> && actualValue <span class="pl-c1">!=</span> <span class="pl-smi">nil</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span> status<span class="pl-kos">:</span> <span class="pl-kos">.</span>fail<span class="pl-kos">,</span> message<span class="pl-kos">:</span> msg<span class="pl-kos">.</span><span class="pl-en">appendedBeNilHint</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span>status<span class="pl-kos">:</span> <span class="pl-kos">.</span>fail<span class="pl-kos">,</span> message<span class="pl-kos">:</span> msg<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span>bool<span class="pl-kos">:</span> matches<span class="pl-kos">,</span> message<span class="pl-kos">:</span> msg<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">In the example above, <code>msg</code> is defined based on the string given to <code>Matcher.define</code>. The code looks akin to:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift let msg = ExpectationMessage.expectedActualValueTo("equal <\(stringify(expectedValue))>")"><pre>// Swift <span class="pl-k">let</span> <span class="pl-s1">msg</span> <span class="pl-c1">=</span> <span class="pl-smi">ExpectationMessage</span><span class="pl-kos">.</span><span class="pl-en">expectedActualValueTo</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">equal <</span><span class="pl-kos">\(</span><span class="pl-en">stringify</span><span class="pl-kos">(</span>expectedValue<span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-s">></span><span class="pl-s">"</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Full Customization</h3><a id="user-content-full-customization" class="anchor" aria-label="Permalink: Full Customization" href="#full-customization"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To fully customize the behavior of the Matcher, use the overload that expects a <code>MatcherResult</code> to be returned.</p> <p dir="auto">Along with <code>MatcherResult</code>, there are other <code>ExpectationMessage</code> enum values you can use:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public indirect enum ExpectationMessage { // Emits standard error message: // eg - "expected to <message>, got <actual>" case expectedActualValueTo(/* message: */ String) // Allows any free-form message // eg - "<message>" case fail(/* message: */ String) // Emits standard error message with a custom actual value instead of the default. // eg - "expected to <message>, got <actual>" case expectedCustomValueTo(/* message: */ String, /* actual: */ String) // Emits standard error message without mentioning the actual value // eg - "expected to <message>" case expectedTo(/* message: */ String) // ... }"><pre><span class="pl-k">public</span> <span class="pl-k">indirect</span> <span class="pl-k">enum</span> <span class="pl-smi">ExpectationMessage</span> <span class="pl-kos">{</span> // Emits standard error message: // eg - "expected to <message>, got <actual>" <span class="pl-k">case</span> expectedActualValueTo<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // Allows any free-form message // eg - "<message>" <span class="pl-k">case</span> fail<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // Emits standard error message with a custom actual value instead of the default. // eg - "expected to <message>, got <actual>" <span class="pl-k">case</span> expectedCustomValueTo<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">,</span> /* actual: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // Emits standard error message without mentioning the actual value // eg - "expected to <message>" <span class="pl-k">case</span> expectedTo<span class="pl-kos">(</span>/* message: */ <span class="pl-smi">String</span><span class="pl-kos">)</span> // ... <span class="pl-kos">}</span></pre></div> <p dir="auto">For matchers that compose other matchers, there are a handful of helper functions to annotate messages.</p> <p dir="auto"><code>appended(message: String)</code> is used to append to the original failure message:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// produces "expected to be true, got <actual> (use beFalse() for inverse)" // appended message do show up inline in Xcode. .expectedActualValueTo("be true").appended(message: " (use beFalse() for inverse)")"><pre>// produces "expected to be true, got <actual> (use beFalse() for inverse)" // appended message do show up inline in Xcode. <span class="pl-kos">.</span>expectedActualValueTo<span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">be true</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">appended</span><span class="pl-kos">(</span>message<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s"> (use beFalse() for inverse)</span><span class="pl-s">"</span><span class="pl-kos">)</span></pre></div> <p dir="auto">For a more comprehensive message that spans multiple lines, use <code>appended(details: String)</code> instead:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// produces "expected to be true, got <actual>\n\nuse beFalse() for inverse\nor use beNil()" // details do not show inline in Xcode, but do show up in test logs. .expectedActualValueTo("be true").appended(details: "use beFalse() for inverse\nor use beNil()")"><pre>// produces "expected to be true, got <actual>\n\nuse beFalse() for inverse\nor use beNil()" // details do not show inline in Xcode, but do show up in test logs. <span class="pl-kos">.</span>expectedActualValueTo<span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">be true</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">appended</span><span class="pl-kos">(</span>details<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">use beFalse() for inverse</span><span class="pl-s">\n</span><span class="pl-s">or use beNil()</span><span class="pl-s">"</span><span class="pl-kos">)</span></pre></div> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Asynchronous Matchers</h2><a id="user-content-asynchronous-matchers" class="anchor" aria-label="Permalink: Asynchronous Matchers" href="#asynchronous-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To write matchers against async expressions, return an instance of <code>AsyncMatcher</code>. The closure passed to <code>AsyncMatcher</code> is async, and the expression you evaluate is also asynchronous and needs to be awaited on.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift actor CallRecorder<Arguments> { private(set) var calls: [Arguments] = [] func record(call: Arguments) { calls.append(call) } } func beCalled<Argument: Equatable>(with arguments: Argument) -> AsyncMatcher<CallRecorder<Argument>> { AsyncMatcher { (expression: AsyncExpression<CallRecorder<Argument>>) in let message = ExpectationMessage.expectedActualValueTo("be called with \(arguments)") guard let calls = try await expression.evaluate()?.calls else { return MatcherResult(status: .fail, message: message.appendedBeNilHint()) } return MatcherResult(bool: calls.contains(args), message: message.appended(details: "called with \(calls)")) } }"><pre>// Swift <span class="pl-k">actor</span> <span class="pl-smi">CallRecorder</span><span class="pl-c1"><</span>Arguments<span class="pl-c1">></span> <span class="pl-kos">{</span> <span class="pl-k">private<span class="pl-kos">(</span>set<span class="pl-kos">)</span></span> <span class="pl-k">var</span> <span class="pl-s1"><span class="pl-c1">calls</span></span><span class="pl-kos">:</span> <span class="pl-kos">[</span><span class="pl-smi">Arguments</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-kos">[</span><span class="pl-kos">]</span> <span class="pl-en">func</span> record<span class="pl-kos">(</span>call<span class="pl-kos">:</span> <span class="pl-smi">Arguments</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> calls<span class="pl-kos">.</span><span class="pl-en">append</span><span class="pl-kos">(</span>call<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-en">func</span> beCalled<span class="pl-c1"><</span>Argument<span class="pl-kos">:</span> <span class="pl-smi">Equatable</span><span class="pl-c1">></span><span class="pl-kos">(</span>with arguments<span class="pl-kos">:</span> <span class="pl-smi">Argument</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">AsyncMatcher</span><span class="pl-c1"><</span><span class="pl-smi">CallRecorder</span><span class="pl-c1"><</span><span class="pl-smi">Argument</span><span class="pl-c1">></span><span class="pl-c1">></span> <span class="pl-kos">{</span> <span class="pl-en">AsyncMatcher</span> <span class="pl-kos">{</span> <span class="pl-kos">(</span>expression<span class="pl-kos">:</span> <span class="pl-smi">AsyncExpression</span><span class="pl-c1"><</span><span class="pl-smi">CallRecorder</span><span class="pl-c1"><</span><span class="pl-smi">Argument</span><span class="pl-c1">></span><span class="pl-c1">></span><span class="pl-kos">)</span> <span class="pl-k">in</span> <span class="pl-k">let</span> <span class="pl-s1">message</span> <span class="pl-c1">=</span> <span class="pl-smi">ExpectationMessage</span><span class="pl-kos">.</span><span class="pl-en">expectedActualValueTo</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">be called with </span><span class="pl-kos">\(</span>arguments<span class="pl-kos">)</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-k">guard</span> <span class="pl-k">let</span> calls <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-k">await</span> expression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-c1"><span class="pl-c1">?</span></span><span class="pl-kos">.</span>calls <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span>status<span class="pl-kos">:</span> <span class="pl-kos">.</span>fail<span class="pl-kos">,</span> message<span class="pl-kos">:</span> message<span class="pl-kos">.</span><span class="pl-en">appendedBeNilHint</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-en">MatcherResult</span><span class="pl-kos">(</span>bool<span class="pl-kos">:</span> calls<span class="pl-kos">.</span><span class="pl-en">contains</span><span class="pl-kos">(</span>args<span class="pl-kos">)</span><span class="pl-kos">,</span> message<span class="pl-kos">:</span> message<span class="pl-kos">.</span><span class="pl-en">appended</span><span class="pl-kos">(</span>details<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">called with </span><span class="pl-kos">\(</span>calls<span class="pl-kos">)</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">In this example, we created an actor to act as an object to record calls to an async function. Then, we created the <code>beCalled(with:)</code> matcher to check if the actor has received a call with the given arguments.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Supporting Objective-C</h2><a id="user-content-supporting-objective-c" class="anchor" aria-label="Permalink: Supporting Objective-C" href="#supporting-objective-c"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To use a custom matcher written in Swift from Objective-C, you'll have to extend the <code>NMBMatcher</code> class, adding a new class method for your custom matcher. The example below defines the class method <code>+[NMBMatcher beNilMatcher]</code>:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Swift extension NMBMatcher { @objc public class func beNilMatcher() -> NMBMatcher { return NMBMatcher { actualExpression in return try beNil().satisfies(actualExpression).toObjectiveC() } } }"><pre>// Swift <span class="pl-k">extension</span> <span class="pl-smi">NMBMatcher</span> <span class="pl-kos">{</span> <span class="pl-s1">@<span class="pl-smi">objc</span></span> <span class="pl-k">public</span> <span class="pl-k"><span class="pl-k">class</span></span> <span class="pl-en">func</span> beNilMatcher<span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">NMBMatcher</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">NMBMatcher</span> <span class="pl-kos">{</span> actualExpression <span class="pl-k">in</span> <span class="pl-k">return</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">beNil</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">satisfies</span><span class="pl-kos">(</span>actualExpression<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toObjectiveC</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <p dir="auto">The above allows you to use the matcher from Objective-C:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(actual).to([NMBMatcher beNilMatcher]());"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(actual).to([NMBMatcher <span class="pl-c1">beNilMatcher</span>]());</pre></div> <p dir="auto">To make the syntax easier to use, define a C function that calls the class method:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C FOUNDATION_EXPORT NMBMatcher *beNil() { return [NMBMatcher beNilMatcher]; }"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> FOUNDATION_EXPORT NMBMatcher *<span class="pl-en">beNil</span>() { <span class="pl-k">return</span> [NMBMatcher <span class="pl-c1">beNilMatcher</span>]; }</pre></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Properly Handling <code>nil</code> in Objective-C Matchers</h3><a id="user-content-properly-handling-nil-in-objective-c-matchers" class="anchor" aria-label="Permalink: Properly Handling nil in Objective-C Matchers" href="#properly-handling-nil-in-objective-c-matchers"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">When supporting Objective-C, make sure you handle <code>nil</code> appropriately. Like <a href="https://github.com/pivotal/cedar/issues/100" data-hovercard-type="issue" data-hovercard-url="/cedarbdd/cedar/issues/100/hovercard">Cedar</a>, <strong>most matchers do not match with nil</strong>. This is to bring prevent test writers from being surprised by <code>nil</code> values where they did not expect them.</p> <p dir="auto">Nimble provides the <code>beNil</code> matcher function for test writer that want to make expectations on <code>nil</code> objects:</p> <div class="highlight highlight-source-objc notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Objective-C expect(nil).to(equal(nil)); // fails expect(nil).to(beNil()); // passes"><pre><span class="pl-c"><span class="pl-c">//</span> Objective-C</span> <span class="pl-en">expect</span>(<span class="pl-c1">nil</span>).to(equal(<span class="pl-c1">nil</span>)); <span class="pl-c"><span class="pl-c">//</span> fails</span> <span class="pl-en">expect</span>(<span class="pl-c1">nil</span>).to(beNil()); <span class="pl-c"><span class="pl-c">//</span> passes</span></pre></div> <p dir="auto">If your matcher does not want to match with nil, you use <code>Matcher.define</code> or <code>Matcher.simple</code>. Using those factory methods will automatically generate expected value failure messages when they're nil.</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public func beginWith<S: Sequence>(_ startingElement: S.Element) -> Matcher<S> where S.Element: Equatable { return Matcher.simple("begin with <\(startingElement)>") { actualExpression in guard let actualValue = try actualExpression.evaluate() else { return .fail } var actualGenerator = actualValue.makeIterator() return MatcherStatus(bool: actualGenerator.next() == startingElement) } } extension NMBMatcher { @objc public class func beginWithMatcher(_ expected: Any) -> NMBMatcher { return NMBMatcher { actualExpression in let actual = try actualExpression.evaluate() let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return try beginWith(expected).satisfies(expr).toObjectiveC() } } }"><pre><span class="pl-k">public</span> <span class="pl-en">func</span> beginWith<span class="pl-c1"><</span>S<span class="pl-kos">:</span> <span class="pl-smi">Sequence</span><span class="pl-c1">></span><span class="pl-kos">(</span>_ startingElement<span class="pl-kos">:</span> <span class="pl-smi">S</span><span class="pl-kos">.</span><span class="pl-smi">Element</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">Matcher</span><span class="pl-c1"><</span><span class="pl-smi">S</span><span class="pl-c1">></span> <span class="pl-k">where</span> S<span class="pl-kos">.</span>Element<span class="pl-kos">:</span> <span class="pl-smi">Equatable</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-smi">Matcher</span><span class="pl-kos">.</span><span class="pl-en">simple</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">begin with <</span><span class="pl-kos">\(</span>startingElement<span class="pl-kos">)</span><span class="pl-s">></span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> actualExpression <span class="pl-k">in</span> <span class="pl-k">guard</span> <span class="pl-k">let</span> actualValue <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> actualExpression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">else</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-kos">.</span>fail <span class="pl-kos">}</span> <span class="pl-k">var</span> <span class="pl-s1">actualGenerator</span> <span class="pl-c1">=</span> actualValue<span class="pl-kos">.</span><span class="pl-en">makeIterator</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">return</span> <span class="pl-en">MatcherStatus</span><span class="pl-kos">(</span>bool<span class="pl-kos">:</span> actualGenerator<span class="pl-kos">.</span><span class="pl-en">next</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">==</span> startingElement<span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-k">extension</span> <span class="pl-smi">NMBMatcher</span> <span class="pl-kos">{</span> <span class="pl-s1">@<span class="pl-smi">objc</span></span> <span class="pl-k">public</span> <span class="pl-k"><span class="pl-k">class</span></span> <span class="pl-en">func</span> beginWithMatcher<span class="pl-kos">(</span>_ expected<span class="pl-kos">:</span> <span class="pl-smi">Any</span><span class="pl-kos">)</span> <span class="pl-c1">-></span> <span class="pl-smi">NMBMatcher</span> <span class="pl-kos">{</span> <span class="pl-k">return</span> <span class="pl-en">NMBMatcher</span> <span class="pl-kos">{</span> actualExpression <span class="pl-k">in</span> <span class="pl-k">let</span> <span class="pl-s1">actual</span> <span class="pl-c1">=</span> <span class="pl-c1"><span class="pl-k">try</span></span> actualExpression<span class="pl-kos">.</span><span class="pl-en">evaluate</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-k">let</span> <span class="pl-s1">expr</span> <span class="pl-c1">=</span> actualExpression<span class="pl-kos">.</span><span class="pl-en">cast</span> <span class="pl-kos">{</span> $0 <span class="pl-k">as?</span> <span class="pl-smi">NMBOrderedCollection</span> <span class="pl-kos">}</span> <span class="pl-k">return</span> <span class="pl-c1"><span class="pl-k">try</span></span> <span class="pl-en">beginWith</span><span class="pl-kos">(</span>expected<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">satisfies</span><span class="pl-kos">(</span>expr<span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">toObjectiveC</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="markdown-heading" dir="auto"><h1 tabindex="-1" class="heading-element" dir="auto">Installing Nimble</h1><a id="user-content-installing-nimble" class="anchor" aria-label="Permalink: Installing Nimble" href="#installing-nimble"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <blockquote> <p dir="auto">Nimble can be used on its own, or in conjunction with its sister project, <a href="https://github.com/Quick/Quick">Quick</a>. To install both Quick and Nimble, follow <a href="https://github.com/Quick/Quick/blob/main/Documentation/en-us/InstallingQuick.md">the installation instructions in the Quick Documentation</a>.</p> </blockquote> <p dir="auto">Nimble can currently be installed in one of two ways: using CocoaPods, or with git submodules.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Installing Nimble as a Submodule</h2><a id="user-content-installing-nimble-as-a-submodule" class="anchor" aria-label="Permalink: Installing Nimble as a Submodule" href="#installing-nimble-as-a-submodule"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To use Nimble as a submodule to test your macOS, iOS or tvOS applications, follow these 4 easy steps:</p> <ol dir="auto"> <li>Clone the Nimble repository</li> <li>Add Nimble.xcodeproj to the Xcode workspace for your project</li> <li>Link Nimble.framework to your test target</li> <li>Start writing expectations!</li> </ol> <p dir="auto">For more detailed instructions on each of these steps, read <a href="https://github.com/Quick/Quick#how-to-install-quick">How to Install Quick</a>. Ignore the steps involving adding Quick to your project in order to install just Nimble.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Installing Nimble via CocoaPods</h2><a id="user-content-installing-nimble-via-cocoapods" class="anchor" aria-label="Permalink: Installing Nimble via CocoaPods" href="#installing-nimble-via-cocoapods"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To use Nimble in CocoaPods to test your macOS, iOS, tvOS or watchOS applications, add Nimble to your podfile and add the <code>use_frameworks!</code> line to enable Swift support for CocoaPods.</p> <div class="highlight highlight-source-ruby notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="platform :ios, '8.0' source 'https://github.com/CocoaPods/Specs.git' # Whatever pods you need for your app go here target 'YOUR_APP_NAME_HERE_Tests', :exclusive => true do use_frameworks! pod 'Nimble' end"><pre><span class="pl-en">platform</span> <span class="pl-pds">:ios</span><span class="pl-kos">,</span> <span class="pl-s">'8.0'</span> <span class="pl-en">source</span> <span class="pl-s">'https://github.com/CocoaPods/Specs.git'</span> <span class="pl-c"># Whatever pods you need for your app go here</span> <span class="pl-en">target</span> <span class="pl-s">'YOUR_APP_NAME_HERE_Tests'</span><span class="pl-kos">,</span> <span class="pl-pds">:exclusive</span> <span class="pl-c1">=></span> <span class="pl-c1">true</span> <span class="pl-k">do</span> <span class="pl-en">use_frameworks!</span> <span class="pl-en">pod</span> <span class="pl-s">'Nimble'</span> <span class="pl-k">end</span></pre></div> <p dir="auto">Finally run <code>pod install</code>.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Installing Nimble via Swift Package Manager</h2><a id="user-content-installing-nimble-via-swift-package-manager" class="anchor" aria-label="Permalink: Installing Nimble via Swift Package Manager" href="#installing-nimble-via-swift-package-manager"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Xcode</h3><a id="user-content-xcode" class="anchor" aria-label="Permalink: Xcode" href="#xcode"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To install Nimble via Xcode's Swift Package Manager Integration: Select your project configuration, then the project tab, then the Package Dependencies tab. Click on the "plus" button at the bottom of the list, then follow the wizard to add Quick to your project. Specify <code>https://github.com/Quick/Nimble.git</code> as the url, and be sure to add Nimble as a dependency of your unit test target, not your app target.</p> <div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">Package.Swift</h3><a id="user-content-packageswift" class="anchor" aria-label="Permalink: Package.Swift" href="#packageswift"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">To use Nimble with Swift Package Manager to test your applications, add Nimble to your <code>Package.Swift</code> and link it with your test target:</p> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// swift-tools-version:5.5 import PackageDescription let package = Package( name: "MyAwesomeLibrary", products: [ // ... ], dependencies: [ // ... .package(url: "https://github.com/Quick/Nimble.git", from: "12.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "MyAwesomeLibrary", dependencies: ...), .testTarget( name: "MyAwesomeLibraryTests", dependencies: ["MyAwesomeLibrary", "Nimble"]), ] )"><pre>// swift-tools-version:5.5 <span class="pl-k">import</span> PackageDescription <span class="pl-k">let</span> <span class="pl-s1"><span class="pl-k">package</span></span> <span class="pl-c1">=</span> <span class="pl-en">Package</span><span class="pl-kos">(</span> name<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">MyAwesomeLibrary</span><span class="pl-s">"</span><span class="pl-kos">,</span> products<span class="pl-kos">:</span> <span class="pl-kos">[</span> // ... <span class="pl-kos">]</span><span class="pl-kos">,</span> dependencies<span class="pl-kos">:</span> <span class="pl-kos">[</span> // ... <span class="pl-kos">.</span><span class="pl-k">package</span><span class="pl-kos">(</span>url<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">https://github.com/Quick/Nimble.git</span><span class="pl-s">"</span><span class="pl-kos">,</span> from<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">12.0.0</span><span class="pl-s">"</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-kos">]</span><span class="pl-kos">,</span> targets<span class="pl-kos">:</span> <span class="pl-kos">[</span> // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. <span class="pl-kos">.</span>target<span class="pl-kos">(</span> name<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">MyAwesomeLibrary</span><span class="pl-s">"</span><span class="pl-kos">,</span> dependencies<span class="pl-kos">:</span> <span class="pl-c1">...</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-kos">.</span>testTarget<span class="pl-kos">(</span> name<span class="pl-kos">:</span> <span class="pl-s">"</span><span class="pl-s">MyAwesomeLibraryTests</span><span class="pl-s">"</span><span class="pl-kos">,</span> dependencies<span class="pl-kos">:</span> <span class="pl-kos">[</span><span class="pl-s">"</span><span class="pl-s">MyAwesomeLibrary</span><span class="pl-s">"</span><span class="pl-kos">,</span> <span class="pl-s">"</span><span class="pl-s">Nimble</span><span class="pl-s">"</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">,</span> <span class="pl-kos">]</span> <span class="pl-kos">)</span></pre></div> <p dir="auto">Please note that if you install Nimble using Swift Package Manager, then <code>raiseException</code> is not available.</p> <div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">Using Nimble without XCTest</h2><a id="user-content-using-nimble-without-xctest" class="anchor" aria-label="Permalink: Using Nimble without XCTest" href="#using-nimble-without-xctest"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Nimble is integrated with XCTest to allow it work well when used in Xcode test bundles, however it can also be used in a standalone app. After installing Nimble using one of the above methods, there are two additional steps required to make this work.</p> <ol dir="auto"> <li>Create a custom assertion handler and assign an instance of it to the global <code>NimbleAssertionHandler</code> variable. For example:</li> </ol> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="class MyAssertionHandler : AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if (!assertion) { print("Expectation failed: \(message.stringValue)") } } }"><pre><span class="pl-k">class</span> <span class="pl-smi">MyAssertionHandler</span> <span class="pl-kos">:</span> <span class="pl-smi">AssertionHandler</span> <span class="pl-kos">{</span> <span class="pl-en">func</span> assert<span class="pl-kos">(</span>assertion<span class="pl-kos">:</span> <span class="pl-smi">Bool</span><span class="pl-kos">,</span> message<span class="pl-kos">:</span> <span class="pl-smi">FailureMessage</span><span class="pl-kos">,</span> location<span class="pl-kos">:</span> <span class="pl-smi">SourceLocation</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-k">if</span> <span class="pl-kos">(</span>!assertion<span class="pl-kos">)</span> <span class="pl-kos">{</span> <span class="pl-en">print</span><span class="pl-kos">(</span><span class="pl-s">"</span><span class="pl-s">Expectation failed: </span><span class="pl-kos">\(</span>message<span class="pl-kos">.</span>stringValue<span class="pl-kos">)</span><span class="pl-s">"</span><span class="pl-kos">)</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span> <span class="pl-kos">}</span></pre></div> <div class="highlight highlight-source-swift notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// Somewhere before you use any assertions NimbleAssertionHandler = MyAssertionHandler()"><pre>// Somewhere before you use any assertions NimbleAssertionHandler <span class="pl-c1">=</span> <span class="pl-en">MyAssertionHandler</span><span class="pl-kos">(</span><span class="pl-kos">)</span></pre></div> <ol start="2" dir="auto"> <li>Add a post-build action to fix an issue with the Swift XCTest support library being unnecessarily copied into your app</li> </ol> <ul dir="auto"> <li>Edit your scheme in Xcode, and navigate to Build -> Post-actions</li> <li>Click the "+" icon and select "New Run Script Action"</li> <li>Open the "Provide build settings from" dropdown and select your target</li> <li>Enter the following script contents:</li> </ul> <div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="rm "${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib""><pre class="notranslate"><code>rm "${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib" </code></pre></div> <p dir="auto">You can now use Nimble assertions in your code and handle failures as you see fit.</p> </article></div></div></div></div></div> <!-- --> <!-- --> <script type="application/json" id="__PRIMER_DATA_:R0:__">{"resolvedServerColorMode":"day"}</script></div> </react-partial> <input type="hidden" data-csrf="true" value="fnFcAOygYNV9Cp1qx8VSVKlYG2xjxM+pOmAyI14DB9pRkbyQEYx7E6fDtH6NupazNMkr4E2x48HjYDlJr6JTJg==" /> </div> <div data-view-component="true" class="Layout-sidebar"> <div class="BorderGrid about-margin" data-pjax> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <div class="hide-sm hide-md"> <h2 class="mb-3 h4">About</h2> <p class="f4 my-3"> A Matcher Framework for Swift and Objective-C </p> <h3 class="sr-only">Resources</h3> <div class="mt-2"> <a class="Link--muted" data-analytics-event="{"category":"Repository Overview","action":"click","label":"location:sidebar;file:readme"}" href="#readme-ov-file"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-book mr-2"> <path d="M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.743 3.743 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574ZM8.755 4.75l-.004 7.322a3.752 3.752 0 0 1 1.992-.572H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.25Z"></path> </svg> Readme </a> </div> <h3 class="sr-only">License</h3> <div class="mt-2"> <a href="#Apache-2.0-1-ov-file" class="Link--muted" data-analytics-event="{"category":"Repository Overview","action":"click","label":"location:sidebar;file:license"}" > <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-law mr-2"> <path d="M8.75.75V2h.985c.304 0 .603.08.867.231l1.29.736c.038.022.08.033.124.033h2.234a.75.75 0 0 1 0 1.5h-.427l2.111 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.006.005-.01.01-.045.04c-.21.176-.441.327-.686.45C14.556 10.78 13.88 11 13 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L12.178 4.5h-.162c-.305 0-.604-.079-.868-.231l-1.29-.736a.245.245 0 0 0-.124-.033H8.75V13h2.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5h2.5V3.5h-.984a.245.245 0 0 0-.124.033l-1.289.737c-.265.15-.564.23-.869.23h-.162l2.112 4.692a.75.75 0 0 1-.154.838l-.53-.53.529.531-.001.002-.002.002-.006.006-.016.015-.045.04c-.21.176-.441.327-.686.45C4.556 10.78 3.88 11 3 11a4.498 4.498 0 0 1-2.023-.454 3.544 3.544 0 0 1-.686-.45l-.045-.04-.016-.015-.006-.006-.004-.004v-.001a.75.75 0 0 1-.154-.838L2.178 4.5H1.75a.75.75 0 0 1 0-1.5h2.234a.249.249 0 0 0 .125-.033l1.288-.737c.265-.15.564-.23.869-.23h.984V.75a.75.75 0 0 1 1.5 0Zm2.945 8.477c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327Zm-10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327Z"></path> </svg> Apache-2.0 license </a> </div> <include-fragment src="/younata/Nimble/hovercards/citation/sidebar_partial?tree_name=main"> </include-fragment> <div class="mt-2"> <a href="/younata/Nimble/activity" data-view-component="true" class="Link Link--muted"><svg text="gray" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-pulse mr-2"> <path d="M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z"></path> </svg> <span class="color-fg-muted">Activity</span></a> </div> <h3 class="sr-only">Stars</h3> <div class="mt-2"> <a href="/younata/Nimble/stargazers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star mr-2"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> <strong>0</strong> stars</a> </div> <h3 class="sr-only">Watchers</h3> <div class="mt-2"> <a href="/younata/Nimble/watchers" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-eye mr-2"> <path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path> </svg> <strong>1</strong> watching</a> </div> <h3 class="sr-only">Forks</h3> <div class="mt-2"> <a href="/younata/Nimble/forks" data-view-component="true" class="Link Link--muted"><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> <strong>0</strong> forks</a> </div> <div class="mt-2"> <a class="Link--muted" href="/contact/report-content?content_url=https%3A%2F%2Fgithub.com%2Fyounata%2FNimble&report=younata+%28user%29"> Report repository </a> </div> </div> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame"> <a href="/younata/Nimble/releases" data-view-component="true" class="Link--primary no-underline Link">Releases</a></h2> <a class="Link--primary no-underline" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/younata/Nimble/tags"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-tag"> <path d="M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775Zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25ZM6 5a1 1 0 1 1 0 2 1 1 0 0 1 0-2Z"></path> </svg> <span class="text-bold">67</span> <span class="color-fg-muted">tags</span> </a> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3"> <a href="/users/younata/packages?repo_name=Nimble" data-view-component="true" class="Link--primary no-underline Link d-flex flex-items-center">Packages <span title="0" hidden="hidden" data-view-component="true" class="Counter ml-1">0</span></a></h2> <div class="text-small color-fg-muted" > No packages published <br> </div> </div> </div> <div class="BorderGrid-row"> <div class="BorderGrid-cell"> <h2 class="h4 mb-3">Languages</h2> <div class="mb-2"> <span data-view-component="true" class="Progress"> <span style="background-color:#F05138 !important;;width: 85.2%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#438eff !important;;width: 12.0%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#89e051 !important;;width: 2.6%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> <span style="background-color:#701516 !important;;width: 0.2%;" itemprop="keywords" data-view-component="true" class="Progress-item color-bg-success-emphasis"></span> </span></div> <ul class="list-style-none"> <li class="d-inline"> <span class="d-inline-flex flex-items-center flex-nowrap text-small mr-3"> <svg style="color:#F05138;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Swift</span> <span>85.2%</span> </span> </li> <li class="d-inline"> <span class="d-inline-flex flex-items-center flex-nowrap text-small mr-3"> <svg style="color:#438eff;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Objective-C</span> <span>12.0%</span> </span> </li> <li class="d-inline"> <span class="d-inline-flex flex-items-center flex-nowrap text-small mr-3"> <svg style="color:#89e051;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Shell</span> <span>2.6%</span> </span> </li> <li class="d-inline"> <span class="d-inline-flex flex-items-center flex-nowrap text-small mr-3"> <svg style="color:#701516;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-dot-fill mr-2"> <path d="M8 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8Z"></path> </svg> <span class="color-fg-default text-bold mr-1">Ruby</span> <span>0.2%</span> </span> </li> </ul> </div> </div> </div> </div> </div></div> </div> </div> </turbo-frame> </main> </div> </div> <footer class="footer pt-8 pb-6 f6 color-fg-muted p-responsive" role="contentinfo" > <h2 class='sr-only'>Footer</h2> <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap"> <div class="d-flex flex-items-center flex-shrink-0 mx-2"> <a aria-label="Homepage" title="GitHub" class="footer-octicon mr-2" href="https://github.com"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12 1C5.9225 1 1 5.9225 1 12C1 16.8675 4.14875 20.9787 8.52125 22.4362C9.07125 22.5325 9.2775 22.2025 9.2775 21.9137C9.2775 21.6525 9.26375 20.7862 9.26375 19.865C6.5 20.3737 5.785 19.1912 5.565 18.5725C5.44125 18.2562 4.905 17.28 4.4375 17.0187C4.0525 16.8125 3.5025 16.3037 4.42375 16.29C5.29 16.2762 5.90875 17.0875 6.115 17.4175C7.105 19.0812 8.68625 18.6137 9.31875 18.325C9.415 17.61 9.70375 17.1287 10.02 16.8537C7.5725 16.5787 5.015 15.63 5.015 11.4225C5.015 10.2262 5.44125 9.23625 6.1425 8.46625C6.0325 8.19125 5.6475 7.06375 6.2525 5.55125C6.2525 5.55125 7.17375 5.2625 9.2775 6.67875C10.1575 6.43125 11.0925 6.3075 12.0275 6.3075C12.9625 6.3075 13.8975 6.43125 14.7775 6.67875C16.8813 5.24875 17.8025 5.55125 17.8025 5.55125C18.4075 7.06375 18.0225 8.19125 17.9125 8.46625C18.6138 9.23625 19.04 10.2125 19.04 11.4225C19.04 15.6437 16.4688 16.5787 14.0213 16.8537C14.42 17.1975 14.7638 17.8575 14.7638 18.8887C14.7638 20.36 14.75 21.5425 14.75 21.9137C14.75 22.2025 14.9563 22.5462 15.5063 22.4362C19.8513 20.9787 23 16.8537 23 12C23 5.9225 18.0775 1 12 1Z"></path> </svg> </a> <span> © 2025 GitHub, Inc. </span> </div> <nav aria-label="Footer"> <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3> <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading"> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to Terms","label":"text:terms"}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to privacy","label":"text:privacy"}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to security","label":"text:security"}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to status","label":"text:status"}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to docs","label":"text:docs"}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a> </li> <li class="mx-2"> <a data-analytics-event="{"category":"Footer","action":"go to contact","label":"text:contact"}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a> </li> <li class="mx-2" > <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{"location":"footer","action":"cookies","context":"subfooter","tag":"link","label":"cookies_link_subfooter_footer"}" > Manage cookies </button> </cookie-consent-link> </li> <li class="mx-2"> <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{"location":"footer","action":"dont_share_info","context":"subfooter","tag":"link","label":"dont_share_info_link_subfooter_footer"}" > Do not share my personal information </button> </cookie-consent-link> </li> </ul> </nav> </div> </footer> <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999" data-initial-cookie-consent-allowed="" data-cookie-consent-required="false"></ghcc-consent> <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> You can’t perform that action at this time. </div> <template id="site-details-dialog"> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open> <summary role="button" aria-label="Close dialog"></summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal"> <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div class="octocat-spinner my-6 js-details-dialog-spinner"></div> </details-dialog> </details> </template> <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;"> <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;"> </div> </div> <template id="snippet-clipboard-copy-button"> <div class="zeroclipboard-container position-absolute right-0 top-0"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> <template id="snippet-clipboard-copy-button-unpositioned"> <div class="zeroclipboard-container"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> </div> <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div> <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div> </body> </html>