Patchwork [6,of,6,V3] rust-cpython: prepare for writing tests that require libpython

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 17, 2019, 1:06 p.m.
Message ID <7c40bc952fd3fde2f5e4.1571317597@mimosa>
Download mbox | patch
Permalink /patch/42455/
State New
Headers show

Comments

Yuya Nishihara - Oct. 17, 2019, 1:06 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1571037319 -32400
#      Mon Oct 14 16:15:19 2019 +0900
# Node ID 7c40bc952fd3fde2f5e4fd123d39e98af590f3d7
# Parent  33aedb3cee1646ea0cb4a4b82bdd64a21a39b5db
rust-cpython: prepare for writing tests that require libpython

What I wanted is to disable the "cpython/extension-module<ver>" feature
while building tests executable, but that seems not doable. Instead,
this patch adds new features dedicated for tests.

The make rule is extracted so that we can easily run cargo tests.

Added a minimal test of ref-sharing as an example. More tests will follow.

Patch

diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -113,7 +113,7 @@  check: tests
 tests:
         # Run Rust tests if cargo is installed
 	if command -v $(CARGO) >/dev/null 2>&1; then \
-		cd $(HGROOT)/rust/hg-cpython && $(CARGO) test --quiet --all; \
+		$(MAKE) rust-tests; \
 	fi
 	cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
 
@@ -127,6 +127,13 @@  testpy-%:
         $(MAKE) -f $(HGROOT)/contrib/Makefile.python PYTHONVER=$* PREFIX=$(HGPYTHONS)/$* python )
 	cd tests && $(HGPYTHONS)/$*/bin/python run-tests.py $(TESTFLAGS)
 
+rust-tests: py_feature = $(shell $(PYTHON) -c \
+ 'import sys; print(["python27-bin", "python3-bin"][sys.version_info[0] >= 3])')
+rust-tests:
+	cd $(HGROOT)/rust/hg-cpython \
+		&& $(CARGO) test --quiet --all \
+			--no-default-features --features "$(py_feature)"
+
 check-code:
 	hg manifest | xargs python contrib/check-code.py
 
@@ -248,6 +255,7 @@  osx:
 
 .PHONY: help all local build doc cleanbutpackages clean install install-bin \
 	install-doc install-home install-home-bin install-home-doc \
-	dist dist-notests check tests check-code format-c update-pot \
+	dist dist-notests check tests rust-tests check-code format-c \
+	update-pot \
 	$(packaging_targets) \
 	osx
diff --git a/rust/hg-cpython/Cargo.toml b/rust/hg-cpython/Cargo.toml
--- a/rust/hg-cpython/Cargo.toml
+++ b/rust/hg-cpython/Cargo.toml
@@ -11,9 +11,14 @@  crate-type = ["cdylib"]
 [features]
 default = ["python27"]
 
+# Features to build an extension module:
 python27 = ["cpython/python27-sys", "cpython/extension-module-2-7"]
+python3 = ["cpython/python3-sys", "cpython/extension-module"]
 
-python3 = ["cpython/python3-sys", "cpython/extension-module"]
+# Enable one of these features to build a test executable linked to libpython:
+# e.g. cargo test --no-default-features --features python27-bin
+python27-bin = ["cpython/python27-sys"]
+python3-bin = ["cpython/python3-sys"]
 
 [dependencies]
 hg-core = { path = "../hg-core" }
diff --git a/rust/hg-cpython/src/lib.rs b/rust/hg-cpython/src/lib.rs
--- a/rust/hg-cpython/src/lib.rs
+++ b/rust/hg-cpython/src/lib.rs
@@ -72,3 +72,10 @@  py_module_initializer!(rustext, initrust
     )?;
     Ok(())
 });
+
+#[cfg(not(any(feature = "python27-bin", feature = "python3-bin")))]
+#[test]
+#[ignore]
+fn libpython_must_be_linked_to_run_tests() {
+    // stub function to tell that some tests wouldn't run
+}
diff --git a/rust/hg-cpython/src/ref_sharing.rs b/rust/hg-cpython/src/ref_sharing.rs
--- a/rust/hg-cpython/src/ref_sharing.rs
+++ b/rust/hg-cpython/src/ref_sharing.rs
@@ -490,3 +490,34 @@  macro_rules! py_shared_iterator {
         }
     };
 }
+
+#[cfg(test)]
+#[cfg(any(feature = "python27-bin", feature = "python3-bin"))]
+mod test {
+    use super::*;
+    use cpython::{GILGuard, Python};
+
+    py_class!(class Owner |py| {
+        data string: PySharedRefCell<String>;
+    });
+    py_shared_ref!(Owner, String, string, string_shared);
+
+    fn prepare_env() -> (GILGuard, Owner) {
+        let gil = Python::acquire_gil();
+        let py = gil.python();
+        let owner =
+            Owner::create_instance(py, PySharedRefCell::new("new".to_owned()))
+                .unwrap();
+        (gil, owner)
+    }
+
+    #[test]
+    fn test_borrow_mut_while_leaked() {
+        let (gil, owner) = prepare_env();
+        let py = gil.python();
+        assert!(owner.string_shared(py).borrow_mut().is_ok());
+        let _leaked = owner.string_shared(py).leak_immutable().unwrap();
+        // TODO: will be allowed
+        assert!(owner.string_shared(py).borrow_mut().is_err());
+    }
+}