Skip to content

Commit

Permalink
test: add fixtures to test function codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
Desdaemon committed Jan 20, 2024
1 parent 01d7e83 commit baa304c
Show file tree
Hide file tree
Showing 21 changed files with 150 additions and 50 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frb_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ notify = "6.1.1"
notify-debouncer-mini = "0.4.1"

[dev-dependencies]
pretty_assertions = "1.4.0"
semver = "1.0.12"

[package.metadata.binstall]
Expand Down
6 changes: 6 additions & 0 deletions frb_codegen/src/library/codegen/generator/api_dart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ mod tests {
body("library/codegen/generator/api_dart/mod/simple")
}

#[test]
#[serial]
fn test_functions() -> anyhow::Result<()> {
body("library/codegen/generator/api_dart/mod/functions")
}

fn body(fixture_name: &str) -> anyhow::Result<()> {
configure_opinionated_test_logging();
let test_fixture_dir = get_test_fixture_dir(fixture_name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,19 @@ fn default_value_maybe_to_dart_style(value: &str, enable: bool) -> Cow<str> {
}

fn default_value_to_dart_style(value: &str) -> String {
let mut split = value.split('.');
let enum_name = split.next().unwrap();

let variant_name = split.next().unwrap().to_string();
let variant_name = make_string_keyword_safe(variant_name.to_case(Case::Camel));

format!("{enum_name}.{variant_name}")
match value.split_once('.') {
// If the user is explicitly calling an enum variant's constructor
// i.e. `const Foo.bar()` instead of `Foo.Bar`, we trust that they
// really mean it and don't convert.
Some((enum_name, variant_name))
if !enum_name.starts_with("const ") && !variant_name.contains('(') =>
{
format!(
"{}.{}",
enum_name,
make_string_keyword_safe(variant_name.to_string()).to_case(Case::Camel)
)
}
_ => value.to_string(),
}
}
2 changes: 1 addition & 1 deletion frb_codegen/src/library/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::codegen::dumper::Dumper;
use crate::codegen::misc::GeneratorProgressBarPack;
use crate::codegen::parser::reader::CachedRustReader;
pub use config::config::{Config, MetaConfig};
pub use config::config_parser::*;

pub use dumper::internal_config::ConfigDumpContent;
use log::debug;

Expand Down
34 changes: 21 additions & 13 deletions frb_codegen/src/library/commands/cargo_expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use crate::codegen::dumper::Dumper;
use crate::codegen::ConfigDumpContent;
use crate::command_args;
use crate::library::commands::command_runner::execute_command;

use anyhow::{bail, Context, Result};
use itertools::Itertools;
use lazy_static::lazy_static;
use log::{debug, info, warn};
use regex::Regex;

use std::borrow::Cow;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use std::{env, fs};

#[derive(Default)]
Expand Down Expand Up @@ -41,7 +44,10 @@ impl CachedCargoExpand {

let expanded = match self.cache.entry(rust_crate_dir.to_owned()) {
Occupied(entry) => entry.into_mut(),
Vacant(entry) => entry.insert(run_cargo_expand(rust_crate_dir, dumper, true)?),
Vacant(entry) => entry.insert(
unwrap_frb_attrs_in_doc(&run_cargo_expand(rust_crate_dir, dumper, true)?)
.into_owned(),
),
};

extract_module(expanded, module)
Expand Down Expand Up @@ -93,7 +99,7 @@ fn run_cargo_expand(
"--theme=none",
"--ugly",
"--config",
"build.rustflags=\"--cfg frb_expand\""
r#"build.rustflags="--cfg frb_expand""#
);

let output = execute_command("cargo", &args, Some(rust_crate_dir), None)
Expand All @@ -114,20 +120,22 @@ fn run_cargo_expand(
// frb-coverage:ignore-end
}

let mut stdout_lines = stdout.lines();
stdout_lines.next();
let ans = stdout_lines.join("\n");
static PATTERN: OnceLock<Regex> = OnceLock::new();
let pattern = PATTERN.get_or_init(|| {
Regex::new(r####"#\[doc =[\s\n]*r###"frb_marker: ([\s\S]*?)"###]"####).unwrap()
});
let ans = pattern.replace_all(&ans, "$1").into_owned();

let ans = stdout.lines().skip(1).join("\n");
dumper.dump_str(ConfigDumpContent::Source, "cargo_expand.rs", &ans)?;

Ok(ans)
}

/// Turns `#[doc = "frb_marker: .."]` back into `#[frb(..)]`, usually produced
/// as a side-effect of cargo-expand.
// NOTE: The amount of pounds must match exactly with the implementation in frb_macros
fn unwrap_frb_attrs_in_doc(code: &str) -> Cow<str> {
lazy_static! {
static ref PATTERN: Regex =
Regex::new(r####"#\[doc =[\s\n]*r###"frb_marker: ([\s\S]*?)"###]"####).unwrap();
}
PATTERN.replace_all(code, "$1")
}

fn install_cargo_expand() -> Result<()> {
execute_command(
"cargo",
Expand Down
2 changes: 1 addition & 1 deletion frb_codegen/src/library/commands/command_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ macro_rules! command_run {
}};
}

/// Formats a list of [`PathBuf`]s using the syntax detailed in [`run`].
/// Formats a list of [`PathBuf`]s using the syntax detailed in [`command_run`].
#[doc(hidden)]
#[macro_export]
macro_rules! command_args {
Expand Down
4 changes: 2 additions & 2 deletions frb_codegen/src/library/integration/integrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn integrate(config: IntegrateConfig) -> Result<()> {
fn modify_permissions(dart_root: &Path) -> Result<()> {
let dir_cargokit = dart_root.join("rust_builder").join("cargokit");

#[cfg(not(windows))]
#[cfg(unix)]
{
set_permission_executable(&dir_cargokit.join("build_pod.sh"))?;
set_permission_executable(&dir_cargokit.join("run_build_tool.sh"))?;
Expand All @@ -82,7 +82,7 @@ fn setup_cargokit_dependencies(dart_root: &Path) -> Result<()> {
flutter_pub_get(&build_tool_dir)
}

#[cfg(not(windows))]
#[cfg(unix)]
fn set_permission_executable(path: &Path) -> Result<()> {
use std::os::unix::fs::PermissionsExt;

Expand Down
30 changes: 23 additions & 7 deletions frb_codegen/src/library/utils/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,43 @@ pub(crate) fn json_golden_test(
let actual: Value = serde_json::from_str(&actual_str)?;
debug!("json_golden_test sanitizers={sanitizers:?} actual:\n{actual_str}");

raw_golden_test(actual, &actual_str, matcher_path, |x| {
Ok(serde_json::from_str(&x)?)
})
raw_golden_test(
actual,
&actual_str,
matcher_path,
|x| Ok(serde_json::from_str(&x)?),
None,
)
}

pub(crate) fn text_golden_test(actual: String, matcher_path: &Path) -> anyhow::Result<()> {
raw_golden_test(actual.clone(), &actual, matcher_path, |x| {
raw_golden_test(
actual.clone(),
&actual,
matcher_path,
// Otherwise tests in macos/linux passes but fails on windows
Ok(x.replace("\r\n", "\n"))
})
|x| Ok(x.replace("\r\n", "\n")),
Some(|expect, actual| {
#[cfg(test)]
use pretty_assertions::assert_str_eq as assert_eq;
assert_eq!(expect, actual);
}),
)
}

fn raw_golden_test<T, F>(
actual: T,
actual_str: &str,
matcher_path: &Path,
deserializer: F,
asserter: Option<fn(&T, &T)>,
) -> anyhow::Result<()>
where
T: Eq + Debug,
F: Fn(String) -> anyhow::Result<T>,
{
#[cfg(test)]
use pretty_assertions::assert_eq;
// This is *test* utils, not a part of real codegen, so no need to consider coverage
// frb-coverage:ignore-start
let expect = deserializer(if matcher_path.exists() {
Expand All @@ -64,7 +79,8 @@ where
fs::write(matcher_path, actual_str)?;
}
} else {
assert_eq!(actual, expect);
let asserter = asserter.unwrap_or(|expect, actual| assert_eq!(expect, actual));
asserter(&expect, &actual);
}

Ok(())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "example"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
flutter_rust_bridge_macros.path = "../../../../../../../../frb_macros"

[workspace]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ {VERSION}.

// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import

import 'frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';


Future<void> fnWithDefaultArg({int foo = 1, dynamic hint}) => RustLib.instance.api.fnWithDefaultArg(foo: foo, hint: hint);



Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rust_input: src/api.rs
dart_output: .
c_output: frb_generated.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: fake_dart_package
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[flutter_rust_bridge_macros::frb]
pub fn fn_with_default_arg(#[frb(default = 1)] foo: i32) {
drop(foo);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod api;
2 changes: 1 addition & 1 deletion frb_example/pure_dart_pde/lib/src/rust/api/attribute.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Future<void> handleCustomizedStructTwinNormal(
RustLib.instance.api.handleCustomizedStructTwinNormal(val: val, hint: hint);

Future<UserIdTwinNormal> nextUserIdTwinNormal(
{required UserIdTwinNormal userId, dynamic hint}) =>
{UserIdTwinNormal userId = const UserIdTwinNormal(), dynamic hint}) =>
RustLib.instance.api.nextUserIdTwinNormal(userId: userId, hint: hint);

class CustomizedTwinNormal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Future<void> handleCustomizedStructTwinRustAsync(
.handleCustomizedStructTwinRustAsync(val: val, hint: hint);

Future<UserIdTwinRustAsync> nextUserIdTwinRustAsync(
{required UserIdTwinRustAsync userId, dynamic hint}) =>
{UserIdTwinRustAsync userId = const UserIdTwinRustAsync(),
dynamic hint}) =>
RustLib.instance.api.nextUserIdTwinRustAsync(userId: userId, hint: hint);

class CustomizedTwinRustAsync {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void handleCustomizedStructTwinSync(
RustLib.instance.api.handleCustomizedStructTwinSync(val: val, hint: hint);

UserIdTwinSync nextUserIdTwinSync(
{required UserIdTwinSync userId, dynamic hint}) =>
{UserIdTwinSync userId = const UserIdTwinSync(), dynamic hint}) =>
RustLib.instance.api.nextUserIdTwinSync(userId: userId, hint: hint);

class CustomizedTwinSync {
Expand Down
13 changes: 7 additions & 6 deletions frb_example/pure_dart_pde/lib/src/rust/frb_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ abstract class RustLibApi extends BaseApi {
{required CustomizedTwinNormal val, dynamic hint});

Future<UserIdTwinNormal> nextUserIdTwinNormal(
{required UserIdTwinNormal userId, dynamic hint});
{UserIdTwinNormal userId = const UserIdTwinNormal(), dynamic hint});

void benchmarkVoidSemiSerialize({dynamic hint});

Expand Down Expand Up @@ -735,13 +735,13 @@ abstract class RustLibApi extends BaseApi {
{required CustomizedTwinRustAsync val, dynamic hint});

Future<UserIdTwinRustAsync> nextUserIdTwinRustAsync(
{required UserIdTwinRustAsync userId, dynamic hint});
{UserIdTwinRustAsync userId = const UserIdTwinRustAsync(), dynamic hint});

void handleCustomizedStructTwinSync(
{required CustomizedTwinSync val, dynamic hint});

UserIdTwinSync nextUserIdTwinSync(
{required UserIdTwinSync userId, dynamic hint});
{UserIdTwinSync userId = const UserIdTwinSync(), dynamic hint});

Future<BasicGeneralEnumTwinNormal>
exampleBasicTypeBasicGeneralEnumTwinNormalTwinNormal(
Expand Down Expand Up @@ -3715,7 +3715,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {

@override
Future<UserIdTwinNormal> nextUserIdTwinNormal(
{required UserIdTwinNormal userId, dynamic hint}) {
{UserIdTwinNormal userId = const UserIdTwinNormal(), dynamic hint}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
Expand Down Expand Up @@ -8498,7 +8498,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {

@override
Future<UserIdTwinRustAsync> nextUserIdTwinRustAsync(
{required UserIdTwinRustAsync userId, dynamic hint}) {
{UserIdTwinRustAsync userId = const UserIdTwinRustAsync(),
dynamic hint}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
Expand Down Expand Up @@ -8550,7 +8551,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {

@override
UserIdTwinSync nextUserIdTwinSync(
{required UserIdTwinSync userId, dynamic hint}) {
{UserIdTwinSync userId = const UserIdTwinSync(), dynamic hint}) {
return handler.executeSync(SyncTask(
callFfi: () {
final serializer = SseSerializer(generalizedFrbRustBinding);
Expand Down
Loading

0 comments on commit baa304c

Please sign in to comment.