use futures::future::BoxFuture;
use futures::StreamExt;
use serde_json::{json, Value};
use wiremock::matchers::any;
use wiremock::{Mock, MockServer, ResponseTemplate};
use crate::{EventStream, MisarDev, MisarDevError};
type Call = for<'a> fn(&'a MisarDev) -> BoxFuture<'a, Result<Value, MisarDevError>>;
type StreamCall = for<'a> fn(&'a MisarDev) -> BoxFuture<'a, Result<EventStream, MisarDevError>>;
pub(crate) const OPERATIONS: &[(&str, &str, &str, bool, Call)] = &[
("account.createKey", "POST", "/account/api-keys", true, |d| Box::pin(d.account().create_key(Some(json!({"probe": true}))))),
("account.deleteKey", "DELETE", "/account/api-keys/keyId-1", false, |d| Box::pin(d.account().delete_key("keyId-1"))),
("account.export", "GET", "/account/export", false, |d| Box::pin(d.account().export())),
("account.listKeys", "GET", "/account/api-keys", false, |d| Box::pin(d.account().list_keys())),
("account.updateKey", "PATCH", "/account/api-keys/keyId-1", true, |d| Box::pin(d.account().update_key("keyId-1", Some(json!({"probe": true}))))),
("apiKeys.create", "POST", "/api-keys", true, |d| Box::pin(d.api_keys().create(Some(json!({"probe": true}))))),
("apiKeys.delete", "DELETE", "/api-keys", true, |d| Box::pin(d.api_keys().delete(Some(json!({"probe": true}))))),
("apiKeys.list", "GET", "/api-keys", false, |d| Box::pin(d.api_keys().list(None))),
("audit.list", "GET", "/audit", false, |d| Box::pin(d.audit().list())),
("billing.checkout", "POST", "/billing/checkout", true, |d| Box::pin(d.billing().checkout(Some(json!({"probe": true}))))),
("billing.comparison", "GET", "/billing/comparison", false, |d| Box::pin(d.billing().comparison())),
("billing.plans", "GET", "/billing/plans", false, |d| Box::pin(d.billing().plans())),
("billing.subscription", "GET", "/billing/subscription", false, |d| Box::pin(d.billing().subscription())),
("billing.switchPlan", "POST", "/billing/switch-plan", true, |d| Box::pin(d.billing().switch_plan(Some(json!({"probe": true}))))),
("builds.list", "GET", "/builds", false, |d| Box::pin(d.builds().list(None))),
("chat.completions", "POST", "/v1/chat/completions", true, |d| Box::pin(d.chat().completions(Some(json!({"probe": true}))))),
("checkpoints.delete", "DELETE", "/checkpoints/id-1", false, |d| Box::pin(d.checkpoints().delete("id-1"))),
("checkpoints.restore", "POST", "/checkpoints/id-1/restore", false, |d| Box::pin(d.checkpoints().restore("id-1"))),
("checkpoints.update", "PATCH", "/checkpoints/id-1", true, |d| Box::pin(d.checkpoints().update("id-1", Some(json!({"probe": true}))))),
("closeFriends.add", "POST", "/close-friends", true, |d| Box::pin(d.close_friends().add(Some(json!({"probe": true}))))),
("closeFriends.list", "GET", "/close-friends", false, |d| Box::pin(d.close_friends().list(None))),
("closeFriends.remove", "DELETE", "/close-friends", true, |d| Box::pin(d.close_friends().remove(Some(json!({"probe": true}))))),
("collections.addPost", "POST", "/collections/id-1/items", true, |d| Box::pin(d.collections().add_post("id-1", Some(json!({"probe": true})), None))),
("collections.create", "POST", "/collections", true, |d| Box::pin(d.collections().create(Some(json!({"probe": true}))))),
("collections.delete", "DELETE", "/collections/id-1", false, |d| Box::pin(d.collections().delete("id-1"))),
("collections.list", "GET", "/collections", false, |d| Box::pin(d.collections().list())),
("collections.removePost", "DELETE", "/collections/id-1/items", true, |d| Box::pin(d.collections().remove_post("id-1", Some(json!({"probe": true})), None))),
("collections.update", "PATCH", "/collections/id-1", true, |d| Box::pin(d.collections().update("id-1", Some(json!({"probe": true}))))),
("comments.delete", "DELETE", "/comments/id-1", false, |d| Box::pin(d.comments().delete("id-1"))),
("comments.like", "POST", "/comments/id-1/like", false, |d| Box::pin(d.comments().like("id-1"))),
("comments.unlike", "DELETE", "/comments/id-1/like", false, |d| Box::pin(d.comments().unlike("id-1"))),
("comments.update", "PATCH", "/comments/id-1", true, |d| Box::pin(d.comments().update("id-1", Some(json!({"probe": true}))))),
("connectors.available", "GET", "/connectors/available", false, |d| Box::pin(d.connectors().available())),
("connectors.createConnection", "POST", "/connectors/connections", true, |d| Box::pin(d.connectors().create_connection(Some(json!({"probe": true}))))),
("connectors.deleteConnection", "DELETE", "/connectors/connections/id-1", false, |d| Box::pin(d.connectors().delete_connection("id-1"))),
("connectors.list", "GET", "/connectors", false, |d| Box::pin(d.connectors().list())),
("connectors.listConnections", "GET", "/connectors/connections", false, |d| Box::pin(d.connectors().list_connections(None))),
("connectors.testConnection", "POST", "/connectors/connections/id-1/test", false, |d| Box::pin(d.connectors().test_connection("id-1"))),
("connectors.toggle", "POST", "/connectors/slug-1/toggle", true, |d| Box::pin(d.connectors().toggle("slug-1", Some(json!({"probe": true}))))),
("connectors.updateConnection", "PATCH", "/connectors/connections/id-1", true, |d| Box::pin(d.connectors().update_connection("id-1", Some(json!({"probe": true}))))),
("dm.acceptThread", "POST", "/dm/threads/id-1/accept", false, |d| Box::pin(d.dm().accept_thread("id-1"))),
("dm.createThread", "POST", "/dm/threads", true, |d| Box::pin(d.dm().create_thread(Some(json!({"probe": true}))))),
("dm.createThreadsMute", "POST", "/dm/threads/id-1/mute", false, |d| Box::pin(d.dm().create_threads_mute("id-1"))),
("dm.declineThread", "POST", "/dm/threads/id-1/decline", false, |d| Box::pin(d.dm().decline_thread("id-1"))),
("dm.deleteThreadsMute", "DELETE", "/dm/threads/id-1/mute", false, |d| Box::pin(d.dm().delete_threads_mute("id-1"))),
("dm.listMessages", "GET", "/dm/threads/id-1/messages", false, |d| Box::pin(d.dm().list_messages("id-1", None))),
("dm.listThreads", "GET", "/dm/threads", false, |d| Box::pin(d.dm().list_threads(None))),
("dm.markThreadRead", "POST", "/dm/threads/id-1/read", false, |d| Box::pin(d.dm().mark_thread_read("id-1"))),
("dm.sendMessage", "POST", "/dm/threads/id-1/messages", true, |d| Box::pin(d.dm().send_message("id-1", Some(json!({"probe": true}))))),
("dm.unreadCounts", "GET", "/dm/unread", false, |d| Box::pin(d.dm().unread_counts())),
("domains.checkout", "POST", "/domains/checkout", true, |d| Box::pin(d.domains().checkout(Some(json!({"probe": true}))))),
("domains.createDnsRecord", "POST", "/domains/id-1/dns", true, |d| Box::pin(d.domains().create_dns_record("id-1", Some(json!({"probe": true}))))),
("domains.deleteDnsRecord", "DELETE", "/domains/id-1/dns?recordId=recordId-v", false, |d| Box::pin(d.domains().delete_dns_record("id-1", "recordId-v"))),
("domains.list", "GET", "/domains", false, |d| Box::pin(d.domains().list())),
("domains.listDnsRecords", "GET", "/domains/id-1/dns", false, |d| Box::pin(d.domains().list_dns_records("id-1"))),
("domains.lookup", "GET", "/domains/lookup?domain=domain-v", false, |d| Box::pin(d.domains().lookup("domain-v"))),
("domains.search", "POST", "/domains/search", true, |d| Box::pin(d.domains().search(Some(json!({"probe": true}))))),
("domains.update", "PATCH", "/domains/id-1", true, |d| Box::pin(d.domains().update("id-1", Some(json!({"probe": true}))))),
("feed.following", "GET", "/feed", false, |d| Box::pin(d.feed().following(None))),
("feed.forYou", "GET", "/feed/for-you", false, |d| Box::pin(d.feed().for_you(None))),
("gallery.like", "POST", "/gallery/projectId-1/like", false, |d| Box::pin(d.gallery().like("projectId-1"))),
("gallery.list", "GET", "/gallery", false, |d| Box::pin(d.gallery().list(None))),
("gallery.unlike", "DELETE", "/gallery/projectId-1/like", false, |d| Box::pin(d.gallery().unlike("projectId-1"))),
("github.disconnect", "DELETE", "/github/connection", false, |d| Box::pin(d.github().disconnect())),
("github.getConnection", "GET", "/github/connection", false, |d| Box::pin(d.github().get_connection())),
("highlights.addStory", "POST", "/highlights/id-1/items", true, |d| Box::pin(d.highlights().add_story("id-1", Some(json!({"probe": true}))))),
("highlights.create", "POST", "/highlights", true, |d| Box::pin(d.highlights().create(Some(json!({"probe": true}))))),
("highlights.delete", "DELETE", "/highlights/id-1", false, |d| Box::pin(d.highlights().delete("id-1"))),
("highlights.list", "GET", "/highlights", false, |d| Box::pin(d.highlights().list(None))),
("highlights.removeStory", "DELETE", "/highlights/id-1/items", true, |d| Box::pin(d.highlights().remove_story("id-1", Some(json!({"probe": true}))))),
("highlights.update", "PATCH", "/highlights/id-1", true, |d| Box::pin(d.highlights().update("id-1", Some(json!({"probe": true}))))),
("notifications.getPreferences", "GET", "/notifications/preferences", false, |d| Box::pin(d.notifications().get_preferences())),
("notifications.list", "GET", "/notifications", false, |d| Box::pin(d.notifications().list(None))),
("notifications.markAllRead", "PATCH", "/notifications", true, |d| Box::pin(d.notifications().mark_all_read(Some(json!({"probe": true}))))),
("notifications.markRead", "PATCH", "/notifications/id-1", true, |d| Box::pin(d.notifications().mark_read("id-1", Some(json!({"probe": true}))))),
("notifications.updatePreferences", "PATCH", "/notifications/preferences", true, |d| Box::pin(d.notifications().update_preferences(Some(json!({"probe": true}))))),
("organizations.acceptInvitation", "POST", "/invitations/accept", true, |d| Box::pin(d.organizations().accept_invitation(Some(json!({"probe": true}))))),
("organizations.create", "POST", "/organizations", true, |d| Box::pin(d.organizations().create(Some(json!({"probe": true}))))),
("organizations.createInvitation", "POST", "/organizations/id-1/invitations", true, |d| Box::pin(d.organizations().create_invitation("id-1", Some(json!({"probe": true}))))),
("organizations.list", "GET", "/organizations", false, |d| Box::pin(d.organizations().list())),
("organizations.listInvitations", "GET", "/organizations/id-1/invitations", false, |d| Box::pin(d.organizations().list_invitations("id-1"))),
("organizations.listMembers", "GET", "/organizations/id-1/members", false, |d| Box::pin(d.organizations().list_members("id-1"))),
("organizations.removeMember", "DELETE", "/organizations/id-1/members?userId=userId-v", false, |d| Box::pin(d.organizations().remove_member("id-1", "userId-v"))),
("organizations.revokeInvitation", "DELETE", "/organizations/id-1/invitations?invitationId=invitationId-v", false, |d| Box::pin(d.organizations().revoke_invitation("id-1", "invitationId-v"))),
("organizations.updateMember", "PATCH", "/organizations/id-1/members", true, |d| Box::pin(d.organizations().update_member("id-1", Some(json!({"probe": true}))))),
("posts.create", "POST", "/posts", true, |d| Box::pin(d.posts().create(Some(json!({"probe": true}))))),
("posts.createComment", "POST", "/posts/id-1/comments", true, |d| Box::pin(d.posts().create_comment("id-1", Some(json!({"probe": true}))))),
("posts.get", "GET", "/posts/id-1", false, |d| Box::pin(d.posts().get("id-1"))),
("posts.like", "POST", "/posts/id-1/like", false, |d| Box::pin(d.posts().like("id-1"))),
("posts.list", "GET", "/posts", false, |d| Box::pin(d.posts().list(None))),
("posts.listComments", "GET", "/posts/id-1/comments", false, |d| Box::pin(d.posts().list_comments("id-1", None))),
("posts.listSaved", "GET", "/me/saved", false, |d| Box::pin(d.posts().list_saved(None))),
("posts.save", "POST", "/posts/id-1/save", true, |d| Box::pin(d.posts().save("id-1", Some(json!({"probe": true}))))),
("posts.shareToDm", "POST", "/posts/id-1/share-dm", true, |d| Box::pin(d.posts().share_to_dm("id-1", Some(json!({"probe": true}))))),
("posts.unlike", "DELETE", "/posts/id-1/like", false, |d| Box::pin(d.posts().unlike("id-1"))),
("posts.unsave", "DELETE", "/posts/id-1/save", false, |d| Box::pin(d.posts().unsave("id-1"))),
("posts.update", "PATCH", "/posts/id-1", true, |d| Box::pin(d.posts().update("id-1", Some(json!({"probe": true}))))),
("profile.block", "POST", "/blocks/handle-1", false, |d| Box::pin(d.profile().block("handle-1"))),
("profile.follow", "POST", "/follow/handle-1", true, |d| Box::pin(d.profile().follow("handle-1", Some(json!({"probe": true}))))),
("profile.get", "GET", "/profile/handle-1", false, |d| Box::pin(d.profile().get("handle-1"))),
("profile.getHighlight", "GET", "/profile/handle-1/highlights/id-1", false, |d| Box::pin(d.profile().get_highlight("handle-1", "id-1"))),
("profile.listBlocks", "GET", "/blocks", false, |d| Box::pin(d.profile().list_blocks())),
("profile.listConnections", "GET", "/profile/handle-1/list-1", false, |d| Box::pin(d.profile().list_connections("handle-1", "list-1", None))),
("profile.listHighlights", "GET", "/profile/handle-1/highlights", false, |d| Box::pin(d.profile().list_highlights("handle-1"))),
("profile.mute", "POST", "/mutes/handle-1", true, |d| Box::pin(d.profile().mute("handle-1", Some(json!({"probe": true}))))),
("profile.unblock", "DELETE", "/blocks/handle-1", false, |d| Box::pin(d.profile().unblock("handle-1"))),
("profile.unfollow", "DELETE", "/follow/handle-1", false, |d| Box::pin(d.profile().unfollow("handle-1"))),
("profile.unmute", "DELETE", "/mutes/handle-1", false, |d| Box::pin(d.profile().unmute("handle-1"))),
("projects.addCollaborator", "POST", "/projects/id-1/collaborators", true, |d| Box::pin(d.projects().add_collaborator("id-1", Some(json!({"probe": true}))))),
("projects.archive", "POST", "/projects/id-1/archive", true, |d| Box::pin(d.projects().archive("id-1", Some(json!({"probe": true}))))),
("projects.buildStatus", "GET", "/projects/id-1/build-status", false, |d| Box::pin(d.projects().build_status("id-1"))),
("projects.cancelBuild", "POST", "/projects/id-1/cancel-build", false, |d| Box::pin(d.projects().cancel_build("id-1"))),
("projects.checkSubdomain", "GET", "/projects/id-1/subdomain/check?value=value-v", false, |d| Box::pin(d.projects().check_subdomain("id-1", "value-v"))),
("projects.create", "POST", "/projects", true, |d| Box::pin(d.projects().create(Some(json!({"probe": true}))))),
("projects.createConversation", "POST", "/projects/id-1/conversations", false, |d| Box::pin(d.projects().create_conversation("id-1"))),
("projects.delete", "DELETE", "/projects/id-1", false, |d| Box::pin(d.projects().delete("id-1"))),
("projects.deleteEnv", "DELETE", "/projects/id-1/env?key=key-v", false, |d| Box::pin(d.projects().delete_env("id-1", "key-v"))),
("projects.deleteSkills", "DELETE", "/projects/id-1/skills?slug=slug-v", false, |d| Box::pin(d.projects().delete_skills("id-1", "slug-v"))),
("projects.deploy", "POST", "/projects/id-1/deploy", true, |d| Box::pin(d.projects().deploy("id-1", Some(json!({"probe": true}))))),
("projects.duplicate", "POST", "/projects/id-1/duplicate", false, |d| Box::pin(d.projects().duplicate("id-1"))),
("projects.export", "GET", "/projects/id-1/export", false, |d| Box::pin(d.projects().export("id-1"))),
("projects.get", "GET", "/projects/id-1", false, |d| Box::pin(d.projects().get("id-1"))),
("projects.getBackend", "GET", "/projects/id-1/backend", false, |d| Box::pin(d.projects().get_backend("id-1"))),
("projects.getDeployment", "GET", "/projects/id-1/deploy", false, |d| Box::pin(d.projects().get_deployment("id-1"))),
("projects.getDomain", "GET", "/projects/id-1/domain", false, |d| Box::pin(d.projects().get_domain("id-1"))),
("projects.getEnv", "GET", "/projects/id-1/env", false, |d| Box::pin(d.projects().get_env("id-1"))),
("projects.getKnowledge", "GET", "/projects/id-1/knowledge", false, |d| Box::pin(d.projects().get_knowledge("id-1"))),
("projects.getSkills", "GET", "/projects/id-1/skills", false, |d| Box::pin(d.projects().get_skills("id-1"))),
("projects.getTools", "GET", "/projects/id-1/tools", false, |d| Box::pin(d.projects().get_tools("id-1"))),
("projects.importArtifact", "POST", "/projects/id-1/import-artifact", true, |d| Box::pin(d.projects().import_artifact("id-1", Some(json!({"probe": true}))))),
("projects.list", "GET", "/projects", false, |d| Box::pin(d.projects().list(None))),
("projects.listCheckpoints", "GET", "/projects/id-1/checkpoints", false, |d| Box::pin(d.projects().list_checkpoints("id-1"))),
("projects.listCollaborators", "GET", "/projects/id-1/collaborators", false, |d| Box::pin(d.projects().list_collaborators("id-1"))),
("projects.listConversations", "GET", "/projects/id-1/conversations", false, |d| Box::pin(d.projects().list_conversations("id-1", None))),
("projects.listFiles", "GET", "/projects/id-1/files", false, |d| Box::pin(d.projects().list_files("id-1"))),
("projects.provisionBackend", "POST", "/projects/id-1/backend", true, |d| Box::pin(d.projects().provision_backend("id-1", Some(json!({"probe": true}))))),
("projects.recommendDomains", "GET", "/projects/id-1/domains/recommend", false, |d| Box::pin(d.projects().recommend_domains("id-1"))),
("projects.removeCollaborator", "DELETE", "/projects/id-1/collaborators?collaboratorId=collaboratorId-v", false, |d| Box::pin(d.projects().remove_collaborator("id-1", "collaboratorId-v"))),
("projects.removeDomain", "DELETE", "/projects/id-1/domain", false, |d| Box::pin(d.projects().remove_domain("id-1"))),
("projects.restore", "POST", "/projects/id-1", false, |d| Box::pin(d.projects().restore("id-1"))),
("projects.setDomain", "POST", "/projects/id-1/domain", true, |d| Box::pin(d.projects().set_domain("id-1", Some(json!({"probe": true}))))),
("projects.undeploy", "DELETE", "/projects/id-1/deploy", false, |d| Box::pin(d.projects().undeploy("id-1"))),
("projects.update", "PATCH", "/projects/id-1", true, |d| Box::pin(d.projects().update("id-1", Some(json!({"probe": true}))))),
("projects.updateEnv", "PUT", "/projects/id-1/env", true, |d| Box::pin(d.projects().update_env("id-1", Some(json!({"probe": true}))))),
("projects.updateKnowledge", "PUT", "/projects/id-1/knowledge", true, |d| Box::pin(d.projects().update_knowledge("id-1", Some(json!({"probe": true}))))),
("projects.updateSkills", "PUT", "/projects/id-1/skills", true, |d| Box::pin(d.projects().update_skills("id-1", Some(json!({"probe": true}))))),
("projects.updateSubdomain", "PATCH", "/projects/id-1/subdomain", true, |d| Box::pin(d.projects().update_subdomain("id-1", Some(json!({"probe": true}))))),
("projects.updateTools", "PUT", "/projects/id-1/tools", true, |d| Box::pin(d.projects().update_tools("id-1", Some(json!({"probe": true}))))),
("projects.writeFiles", "POST", "/projects/id-1/files", true, |d| Box::pin(d.projects().write_files("id-1", Some(json!({"probe": true}))))),
("rag.clear", "DELETE", "/rag?projectId=projectId-v", false, |d| Box::pin(d.rag().clear("projectId-v"))),
("rag.index", "POST", "/rag", true, |d| Box::pin(d.rag().index(Some(json!({"probe": true}))))),
("rag.search", "GET", "/rag?projectId=projectId-v", false, |d| Box::pin(d.rag().search("projectId-v", None))),
("reports.create", "POST", "/reports", true, |d| Box::pin(d.reports().create(Some(json!({"probe": true}))))),
("search.code", "GET", "/search", false, |d| Box::pin(d.search().code(None))),
("search.web", "POST", "/v1/search", true, |d| Box::pin(d.search().web(Some(json!({"probe": true}))))),
("skills.get", "GET", "/skills/misarai/slug-1", false, |d| Box::pin(d.skills().get("slug-1"))),
("skills.list", "GET", "/skills/misarai", false, |d| Box::pin(d.skills().list())),
("social.dismissSuggestion", "POST", "/social/suggestions/handle-1/dismiss", false, |d| Box::pin(d.social().dismiss_suggestion("handle-1"))),
("social.listSuggestions", "GET", "/social/suggestions", false, |d| Box::pin(d.social().list_suggestions(None))),
("social.meMutuals", "GET", "/social/me/mutuals", false, |d| Box::pin(d.social().me_mutuals(None))),
("social.relationship", "GET", "/social/relationship/handle-1", false, |d| Box::pin(d.social().relationship("handle-1"))),
("stories.create", "POST", "/stories", true, |d| Box::pin(d.stories().create(Some(json!({"probe": true}))))),
("stories.delete", "DELETE", "/stories/id-1", false, |d| Box::pin(d.stories().delete("id-1"))),
("stories.get", "GET", "/stories/id-1", false, |d| Box::pin(d.stories().get("id-1"))),
("stories.listMyPosts", "GET", "/stories/my-posts", false, |d| Box::pin(d.stories().list_my_posts(None))),
("stories.listViewers", "GET", "/stories/id-1/viewers", false, |d| Box::pin(d.stories().list_viewers("id-1", None))),
("stories.markSeen", "POST", "/stories/id-1/view", false, |d| Box::pin(d.stories().mark_seen("id-1"))),
("stories.reply", "POST", "/stories/id-1/reply", true, |d| Box::pin(d.stories().reply("id-1", Some(json!({"probe": true}))))),
("stories.tray", "GET", "/stories/tray", false, |d| Box::pin(d.stories().tray())),
("tags.get", "GET", "/tags/tag-1", false, |d| Box::pin(d.tags().get("tag-1", None))),
("templates.create", "POST", "/templates", true, |d| Box::pin(d.templates().create(Some(json!({"probe": true}))))),
("templates.delete", "DELETE", "/templates/id-1", false, |d| Box::pin(d.templates().delete("id-1"))),
("templates.get", "GET", "/templates/id-1", false, |d| Box::pin(d.templates().get("id-1"))),
("templates.list", "GET", "/templates", false, |d| Box::pin(d.templates().list(None))),
("templates.remix", "POST", "/templates/remix", true, |d| Box::pin(d.templates().remix(Some(json!({"probe": true}))))),
("templates.update", "PATCH", "/templates/id-1", true, |d| Box::pin(d.templates().update("id-1", Some(json!({"probe": true}))))),
("templates.use", "POST", "/templates/id-1/use", true, |d| Box::pin(d.templates().use_("id-1", Some(json!({"probe": true}))))),
("usage.list", "GET", "/usage", false, |d| Box::pin(d.usage().list(None))),
("usage.plan", "GET", "/usage/plan", false, |d| Box::pin(d.usage().plan())),
("usage.track", "POST", "/usage/track", true, |d| Box::pin(d.usage().track(Some(json!({"probe": true}))))),
];
pub(crate) const STREAMS: &[(&str, &str, &str, bool, StreamCall)] = &[
("chat.studioStream", "POST", "/chat", true, |d| Box::pin(d.chat().studio_stream(Some(json!({"probe": true}))))),
("chat.completionsStream", "POST", "/v1/chat/completions", true, |d| Box::pin(d.chat().completions_stream(Some(json!({"probe": true}))))),
("projects.buildStream", "GET", "/projects/id-1/build-stream", false, |d| Box::pin(d.projects().build_stream("id-1"))),
];
fn client(server: &MockServer) -> MisarDev {
MisarDev::builder()
.api_key("mdk_test_key")
.base_url(format!("{}/dev", server.uri()))
.build()
.expect("client")
}
fn url_of(req: &wiremock::Request) -> String {
match req.url.query() {
Some(q) => format!("{}?{}", req.url.path(), q),
None => req.url.path().to_owned(),
}
}
#[test]
fn table_covers_every_operation() {
assert_eq!(OPERATIONS.len() + STREAMS.len(), super::OPERATION_COUNT);
}
#[tokio::test]
async fn every_generated_method_builds_its_route() {
let server = MockServer::start().await;
for (name, verb, url, has_body, call) in OPERATIONS {
server.reset().await;
Mock::given(any())
.respond_with(ResponseTemplate::new(200).set_body_json(json!({"ok": true})))
.mount(&server)
.await;
let dev = client(&server);
let out = call(&dev).await.unwrap_or_else(|e| panic!("{name}: {e}"));
assert_eq!(out, json!({"ok": true}), "{name}");
let reqs = server.received_requests().await.expect("recording");
assert_eq!(reqs.len(), 1, "{name}");
assert_eq!(reqs[0].method.as_str(), *verb, "{name}");
assert_eq!(url_of(&reqs[0]), format!("/dev{url}"), "{name}");
if *has_body {
let body: Value = serde_json::from_slice(&reqs[0].body).expect("json body");
assert_eq!(body["probe"], json!(true), "{name}");
}
}
}
#[tokio::test]
async fn every_generated_stream_builds_its_route() {
let server = MockServer::start().await;
for (name, verb, url, has_body, call) in STREAMS {
server.reset().await;
Mock::given(any())
.respond_with(
ResponseTemplate::new(200)
.insert_header("content-type", "text/event-stream")
.set_body_string("data: {\"x\":1}\n\n"),
)
.mount(&server)
.await;
let dev = client(&server);
let mut stream = call(&dev).await.unwrap_or_else(|e| panic!("{name}: {e}"));
let mut n = 0;
while let Some(ev) = stream.next().await {
assert_eq!(ev.expect("event").data, json!({"x": 1}), "{name}");
n += 1;
}
assert_eq!(n, 1, "{name}");
let reqs = server.received_requests().await.expect("recording");
assert_eq!(reqs[0].method.as_str(), *verb, "{name}");
assert_eq!(url_of(&reqs[0]), format!("/dev{url}"), "{name}");
if *has_body {
let body: Value = serde_json::from_slice(&reqs[0].body).expect("json body");
assert_eq!(body["probe"], json!(true), "{name}");
}
}
}