diff --git a/packages/typespec-rust/.scripts/tspcompile.js b/packages/typespec-rust/.scripts/tspcompile.js index be9a80bed..413e85e17 100644 --- a/packages/typespec-rust/.scripts/tspcompile.js +++ b/packages/typespec-rust/.scripts/tspcompile.js @@ -79,6 +79,7 @@ const azureHttpSpecsGroup = { 'spector_apiverheader': {input: 'azure/client-generator-core/api-version/header/client.tsp'}, 'spector_apiverpath': {input: 'azure/client-generator-core/api-version/path/client.tsp'}, 'spector_apiverquery': {input: 'azure/client-generator-core/api-version/query/client.tsp'}, + 'spector_client_default_value': {input: 'azure/client-generator-core/client-default-value'}, 'spector_clientinit_default': {input: 'azure/client-generator-core/client-initialization/default'}, 'spector_clientinit_individually': {input: 'azure/client-generator-core/client-initialization/individually'}, 'spector_clientinit_individually_parent': {input: 'azure/client-generator-core/client-initialization/individuallyParent'}, diff --git a/packages/typespec-rust/test/Cargo.lock b/packages/typespec-rust/test/Cargo.lock index c02a0534d..3296d9f14 100644 --- a/packages/typespec-rust/test/Cargo.lock +++ b/packages/typespec-rust/test/Cargo.lock @@ -1954,6 +1954,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "spector_client_default_value" +version = "0.1.0" +dependencies = [ + "azure_core", + "serde", + "tokio", +] + [[package]] name = "spector_clientinit_default" version = "0.1.0" diff --git a/packages/typespec-rust/test/Cargo.toml b/packages/typespec-rust/test/Cargo.toml index 04ff89cbd..e1db7f4c6 100644 --- a/packages/typespec-rust/test/Cargo.toml +++ b/packages/typespec-rust/test/Cargo.toml @@ -20,6 +20,7 @@ members = [ "spector/azure/client-generator-core/api-version/path", "spector/azure/client-generator-core/api-version/query", "spector/azure/client-generator-core/alternate-type", + "spector/azure/client-generator-core/client-default-value", "spector/azure/client-generator-core/client-initialization/default", "spector/azure/client-generator-core/client-initialization/individually", "spector/azure/client-generator-core/client-initialization/individuallyParent", diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/Cargo.toml b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/Cargo.toml new file mode 100644 index 000000000..75cc440c2 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "spector_client_default_value" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[features] +default = ["azure_core/default"] + +[dependencies] +azure_core = { workspace = true } +serde = { workspace = true } + +[dev-dependencies] +tokio = { workspace = true } diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/client_default_value_client.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/client_default_value_client.rs new file mode 100644 index 000000000..9027f670b --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/client_default_value_client.rs @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +use crate::generated::models::{ + ClientDefaultValueClientGetHeaderParameterOptions, + ClientDefaultValueClientGetOperationParameterOptions, + ClientDefaultValueClientGetPathParameterOptions, + ClientDefaultValueClientPutModelPropertyOptions, ModelWithDefaultValues, +}; +use azure_core::{ + error::CheckSuccessOptions, + fmt::SafeDebug, + http::{ + ClientOptions, Method, NoFormat, Pipeline, PipelineSendOptions, Request, RequestContent, + Response, Url, UrlExt, + }, + tracing, Result, +}; + +/// Test for `@clientDefaultValue` decorator. +#[tracing::client] +pub struct ClientDefaultValueClient { + pub(crate) endpoint: Url, + pub(crate) pipeline: Pipeline, +} + +/// Options used when creating a [`ClientDefaultValueClient`](ClientDefaultValueClient) +#[derive(Clone, Default, SafeDebug)] +pub struct ClientDefaultValueClientOptions { + /// Allows customization of the client. + pub client_options: ClientOptions, +} + +impl ClientDefaultValueClient { + /// Creates a new ClientDefaultValueClient requiring no authentication. + /// + /// # Arguments + /// + /// * `endpoint` - Service host + /// * `options` - Optional configuration for the client. + #[tracing::new("_Specs_.Azure.ClientGenerator.Core.ClientDefaultValue")] + pub fn with_no_credential( + endpoint: &str, + options: Option, + ) -> Result { + let options = options.unwrap_or_default(); + let endpoint = Url::parse(endpoint)?; + if !endpoint.scheme().starts_with("http") { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + format!("{endpoint} must use http(s)"), + )); + } + Ok(Self { + endpoint, + pipeline: Pipeline::new( + option_env!("CARGO_PKG_NAME"), + option_env!("CARGO_PKG_VERSION"), + options.client_options, + Vec::default(), + Vec::default(), + None, + ), + }) + } + + /// Returns the Url associated with this client. + pub fn endpoint(&self) -> &Url { + &self.endpoint + } + + /// + /// # Arguments + /// + /// * `options` - Optional parameters for the request. + #[tracing::function("_Specs_.Azure.ClientGenerator.Core.ClientDefaultValue.getHeaderParameter")] + pub async fn get_header_parameter( + &self, + options: Option>, + ) -> Result> { + let options = options.unwrap_or_default(); + let ctx = options.method_options.context.to_borrowed(); + let mut url = self.endpoint.clone(); + url.append_path("/azure/client-generator-core/client-default-value/header-parameter"); + let mut request = Request::new(url, Method::Get); + if let Some(accept) = options.accept.as_ref() { + request.insert_header("accept", accept); + } + if let Some(custom_header) = options.custom_header.as_ref() { + request.insert_header("x-custom-header", custom_header); + } + let rsp = self + .pipeline + .send( + &ctx, + &mut request, + Some(PipelineSendOptions { + check_success: CheckSuccessOptions { + success_codes: &[204], + }, + ..Default::default() + }), + ) + .await?; + Ok(rsp.into()) + } + + /// + /// # Arguments + /// + /// * `options` - Optional parameters for the request. + #[tracing::function( + "_Specs_.Azure.ClientGenerator.Core.ClientDefaultValue.getOperationParameter" + )] + pub async fn get_operation_parameter( + &self, + name: &str, + options: Option>, + ) -> Result> { + let options = options.unwrap_or_default(); + let ctx = options.method_options.context.to_borrowed(); + let mut url = self.endpoint.clone(); + url.append_path("/azure/client-generator-core/client-default-value/operation-parameter"); + let mut query_builder = url.query_builder(); + if let Some(format) = options.format.as_ref() { + query_builder.set_pair("format", format); + } + query_builder.set_pair("name", name); + if let Some(page_size) = options.page_size { + query_builder.set_pair("pageSize", page_size.to_string()); + } + query_builder.build(); + let mut request = Request::new(url, Method::Get); + let rsp = self + .pipeline + .send( + &ctx, + &mut request, + Some(PipelineSendOptions { + check_success: CheckSuccessOptions { + success_codes: &[204], + }, + ..Default::default() + }), + ) + .await?; + Ok(rsp.into()) + } + + /// + /// # Arguments + /// + /// * `options` - Optional parameters for the request. + #[tracing::function("_Specs_.Azure.ClientGenerator.Core.ClientDefaultValue.getPathParameter")] + pub async fn get_path_parameter( + &self, + segment1: &str, + segment2: &str, + options: Option>, + ) -> Result> { + if segment1.is_empty() { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "parameter segment1 cannot be empty", + )); + } + if segment2.is_empty() { + return Err(azure_core::Error::with_message( + azure_core::error::ErrorKind::Other, + "parameter segment2 cannot be empty", + )); + } + let options = options.unwrap_or_default(); + let ctx = options.method_options.context.to_borrowed(); + let mut url = self.endpoint.clone(); + let mut path = String::from("/azure/client-generator-core/client-default-value/path-parameter/{segment1}/{segment2}"); + path = path.replace("{segment1}", segment1); + path = path.replace("{segment2}", segment2); + url.append_path(&path); + let mut request = Request::new(url, Method::Get); + let rsp = self + .pipeline + .send( + &ctx, + &mut request, + Some(PipelineSendOptions { + check_success: CheckSuccessOptions { + success_codes: &[204], + }, + ..Default::default() + }), + ) + .await?; + Ok(rsp.into()) + } + + /// + /// # Arguments + /// + /// * `options` - Optional parameters for the request. + #[tracing::function("_Specs_.Azure.ClientGenerator.Core.ClientDefaultValue.putModelProperty")] + pub async fn put_model_property( + &self, + body: RequestContent, + options: Option>, + ) -> Result> { + let options = options.unwrap_or_default(); + let ctx = options.method_options.context.to_borrowed(); + let mut url = self.endpoint.clone(); + url.append_path("/azure/client-generator-core/client-default-value/model-property"); + let mut request = Request::new(url, Method::Put); + request.insert_header("accept", "application/json"); + request.insert_header("content-type", "application/json"); + request.set_body(body); + let rsp = self + .pipeline + .send( + &ctx, + &mut request, + Some(PipelineSendOptions { + check_success: CheckSuccessOptions { + success_codes: &[200], + }, + ..Default::default() + }), + ) + .await?; + Ok(rsp.into()) + } +} diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/mod.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/mod.rs new file mode 100644 index 000000000..9fc5e32b4 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/clients/mod.rs @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +mod client_default_value_client; +pub use client_default_value_client::*; diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/mod.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/mod.rs new file mode 100644 index 000000000..1f9a1700d --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/mod.rs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +/// Clients used to communicate with the service. +pub mod clients; +/// Contains all the data structures and types used by the client library. +pub mod models; +pub use clients::{ClientDefaultValueClient, ClientDefaultValueClientOptions}; diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/method_options.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/method_options.rs new file mode 100644 index 000000000..93254c41d --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/method_options.rs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +use azure_core::{fmt::SafeDebug, http::ClientMethodOptions}; + +/// Options to be passed to [`ClientDefaultValueClient::get_header_parameter()`](crate::generated::clients::ClientDefaultValueClient::get_header_parameter()) +#[derive(Clone, Default, SafeDebug)] +pub struct ClientDefaultValueClientGetHeaderParameterOptions<'a> { + pub accept: Option, + + pub custom_header: Option, + + /// Allows customization of the method call. + pub method_options: ClientMethodOptions<'a>, +} + +/// Options to be passed to [`ClientDefaultValueClient::get_operation_parameter()`](crate::generated::clients::ClientDefaultValueClient::get_operation_parameter()) +#[derive(Clone, Default, SafeDebug)] +pub struct ClientDefaultValueClientGetOperationParameterOptions<'a> { + pub format: Option, + + /// Allows customization of the method call. + pub method_options: ClientMethodOptions<'a>, + + pub page_size: Option, +} + +/// Options to be passed to [`ClientDefaultValueClient::get_path_parameter()`](crate::generated::clients::ClientDefaultValueClient::get_path_parameter()) +#[derive(Clone, Default, SafeDebug)] +pub struct ClientDefaultValueClientGetPathParameterOptions<'a> { + /// Allows customization of the method call. + pub method_options: ClientMethodOptions<'a>, +} + +/// Options to be passed to [`ClientDefaultValueClient::put_model_property()`](crate::generated::clients::ClientDefaultValueClient::put_model_property()) +#[derive(Clone, Default, SafeDebug)] +pub struct ClientDefaultValueClientPutModelPropertyOptions<'a> { + /// Allows customization of the method call. + pub method_options: ClientMethodOptions<'a>, +} diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/mod.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/mod.rs new file mode 100644 index 000000000..5dfb21b69 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/mod.rs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +mod method_options; +#[allow(clippy::module_inception)] +mod models; +mod models_impl; +pub use method_options::*; +pub use models::*; diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models.rs new file mode 100644 index 000000000..dd6073da6 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models.rs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +use azure_core::fmt::SafeDebug; +use serde::{Deserialize, Serialize}; + +/// Model with client default values on properties. +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] +pub struct ModelWithDefaultValues { + /// Name property with no default value. + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + + /// Retry property with client default value of true. + #[serde(skip_serializing_if = "Option::is_none")] + pub retry: Option, + + /// Tier property with client default value of 'standard'. + #[serde(skip_serializing_if = "Option::is_none")] + pub tier: Option, + + /// Timeout property with client default value of 30. + #[serde(skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models_impl.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models_impl.rs new file mode 100644 index 000000000..2cc631c2f --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/generated/models/models_impl.rs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT. + +use super::ModelWithDefaultValues; +use azure_core::{http::RequestContent, json::to_json, Result}; + +impl TryFrom for RequestContent { + type Error = azure_core::Error; + fn try_from(value: ModelWithDefaultValues) -> Result { + Ok(to_json(&value)?.into()) + } +} diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/lib.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/lib.rs new file mode 100644 index 000000000..cc784e401 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/src/lib.rs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// +// Code generated by Microsoft (R) Rust Code Generator. + +#![cfg_attr(docsrs, feature(doc_cfg))] + +mod generated; +pub use generated::*; diff --git a/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/tests/client_default_value_client_test.rs b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/tests/client_default_value_client_test.rs new file mode 100644 index 000000000..dae002816 --- /dev/null +++ b/packages/typespec-rust/test/spector/azure/client-generator-core/client-default-value/tests/client_default_value_client_test.rs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Licensed under the MIT License. See License.txt in the project root for license information. + +use spector_client_default_value::{ + models::{ + ClientDefaultValueClientGetHeaderParameterOptions, + ClientDefaultValueClientGetOperationParameterOptions, ModelWithDefaultValues, + }, + ClientDefaultValueClient, +}; + +#[tokio::test] +async fn put_model_property() { + let client = + ClientDefaultValueClient::with_no_credential("http://localhost:3000", None).unwrap(); + + let body = ModelWithDefaultValues { + name: Some("test".to_string()), + ..Default::default() + }; + + let res = client + .put_model_property(body.try_into().unwrap(), None) + .await + .unwrap(); + + assert_eq!(res.status(), 200); + + let res = res.into_model().unwrap(); + assert_eq!(res.name, Some("test".to_string())); + assert_eq!(res.timeout, Some(30)); + assert_eq!(res.tier, Some("standard".to_string())); + assert_eq!(res.retry, Some(true)); +} + +#[tokio::test] +async fn get_operation_parameter() { + let client = + ClientDefaultValueClient::with_no_credential("http://localhost:3000", None).unwrap(); + + let res = client + .get_operation_parameter( + "test", + Some(ClientDefaultValueClientGetOperationParameterOptions { + page_size: Some(10), // Supposed to be the default value + format: Some("json".to_string()), // Supposed to be the default value + ..Default::default() + }), + ) + .await + .unwrap(); + + assert_eq!(res.status(), 204); +} + +#[tokio::test] +async fn get_path_parameter() { + let client = + ClientDefaultValueClient::with_no_credential("http://localhost:3000", None).unwrap(); + + let res = client + .get_path_parameter( + "default-segment1", // Supposed to be the default value + "segment2", + None, + ) + .await + .unwrap(); + + assert_eq!(res.status(), 204); +} + +#[tokio::test] +async fn get_header_parameter() { + let client = + ClientDefaultValueClient::with_no_credential("http://localhost:3000", None).unwrap(); + + let res = client + .get_header_parameter(Some(ClientDefaultValueClientGetHeaderParameterOptions { + accept: Some("application/json;odata.metadata=none".to_string()), // Supposed to be the default value + custom_header: Some("default-value".to_string()), // Supposed to be the default value + ..Default::default() + })) + .await + .unwrap(); + + assert_eq!(res.status(), 204); +}