diff --git a/bindings/ffi/RegorusFFI.g.cs b/bindings/ffi/RegorusFFI.g.cs index 84b9ac1..5ea1a60 100644 --- a/bindings/ffi/RegorusFFI.g.cs +++ b/bindings/ffi/RegorusFFI.g.cs @@ -12,7 +12,7 @@ namespace RegorusFFI { internal static unsafe partial class API { - const string __DllName = "regorusc"; + const string __DllName = "regorus_ffi"; diff --git a/bindings/ruby/.tool-versions b/bindings/ruby/.tool-versions index 3294aed..51f617d 100644 --- a/bindings/ruby/.tool-versions +++ b/bindings/ruby/.tool-versions @@ -1 +1 @@ -ruby 3.3.0 +ruby 3.3.1 diff --git a/bindings/ruby/Gemfile b/bindings/ruby/Gemfile index 6f8513c..6230226 100644 --- a/bindings/ruby/Gemfile +++ b/bindings/ruby/Gemfile @@ -7,10 +7,10 @@ gemspec # These gems are required for local development and testing, # but won't be included in the published gem -gem "minitest", "~> 5.22" +gem "minitest", "~> 5.23" gem "rake", "~> 13.2" gem "rake-compiler" gem "rake-compiler-dock" -gem "rubocop", "~> 1.63", require: false +gem "rubocop", "~> 1.64", require: false gem "rubocop-minitest", require: false gem "rubocop-rake", require: false diff --git a/bindings/ruby/Gemfile.lock b/bindings/ruby/Gemfile.lock index b17336a..48a0cfb 100644 --- a/bindings/ruby/Gemfile.lock +++ b/bindings/ruby/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - regorusrb (0.1.0) + regorusrb (0.1.5) rb_sys (~> 0.9.97) GEM @@ -10,12 +10,12 @@ GEM ast (2.4.2) json (2.7.2) language_server-protocol (3.17.0.3) - minitest (5.23.0) + minitest (5.23.1) parallel (1.24.0) parser (3.3.1.0) ast (~> 2.4.1) racc - racc (1.7.3) + racc (1.8.0) rainbow (3.1.1) rake (13.2.1) rake-compiler (1.2.7) @@ -25,7 +25,7 @@ GEM regexp_parser (2.9.2) rexml (3.2.8) strscan (>= 3.0.9) - rubocop (1.63.5) + rubocop (1.64.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -52,14 +52,14 @@ PLATFORMS x86_64-linux DEPENDENCIES - minitest (~> 5.22) + minitest (~> 5.23) rake (~> 13.2) rake-compiler rake-compiler-dock regorusrb! - rubocop (~> 1.63) + rubocop (~> 1.64) rubocop-minitest rubocop-rake BUNDLED WITH - 2.5.7 + 2.5.10 diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index 0313827..53f2b3b 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -93,7 +93,7 @@ puts results_json ## Development -After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +To update the gem version or dependencies within `bindings/ruby/Gemfile.lock`, run `bundle update --gemfile=bindings/ruby/Gemfile` from the project directory, or `cd bindings/ruby && bundle update` -To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). +After checking out the repo, `cd bindings/ruby` and run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. diff --git a/bindings/ruby/ext/regorusrb/Cargo.toml b/bindings/ruby/ext/regorusrb/Cargo.toml index cf6574b..b6888c7 100644 --- a/bindings/ruby/ext/regorusrb/Cargo.toml +++ b/bindings/ruby/ext/regorusrb/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] path = "src/lib.rs" [dependencies] -magnus = { version = "0.6.3" } +magnus = { version = "0.6.4" } regorus = { git = "https://github.com/microsoft/regorus" } -serde_json = "1.0.115" +serde_json = "1.0.117" serde_magnus = "0.8.1" diff --git a/bindings/ruby/ext/regorusrb/src/lib.rs b/bindings/ruby/ext/regorusrb/src/lib.rs index dfd8b0a..6888e48 100644 --- a/bindings/ruby/ext/regorusrb/src/lib.rs +++ b/bindings/ruby/ext/regorusrb/src/lib.rs @@ -191,6 +191,68 @@ impl Engine { fn eval_deny_query(&self, query: String) -> Result { Ok(self.engine.borrow_mut().eval_deny_query(query, false)) } + + fn set_enable_coverage(&self, enable: bool) -> Result<(), Error> { + Ok(self.engine.borrow_mut().set_enable_coverage(enable)) + } + + fn get_coverage_report_as_json(&self) -> Result { + let report = self + .engine + .borrow_mut() + .get_coverage_report() + .map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to get coverage report as json: {}", e), + ) + })?; + + serde_json::to_string(&report).map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to serialize coverage report: {}", e), + ) + }) + } + + fn get_coverage_report_pretty(&self) -> Result { + let report = self + .engine + .borrow_mut() + .get_coverage_report() + .map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to get coverage report: {}", e), + ) + })?; + + report.to_colored_string().map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to convert report to colored string: {}", e), + ) + }) + } + + fn clear_coverage_data(&self) -> Result<(), Error> { + Ok(self.engine.borrow_mut().clear_coverage_data()) + } + + // Print statements can be gathered async instead of printing to stderr + fn set_gather_prints(&self, enable: bool) -> Result<(), Error> { + Ok(self.engine.borrow_mut().set_gather_prints(enable)) + } + + fn take_prints(&self) -> Result, Error> { + self.engine.borrow_mut().take_prints().map_err(|e| { + Error::new( + runtime_error(), + format!("Failed to gather print statement: {}", e), + ) + }) + } } #[magnus::init] @@ -237,5 +299,28 @@ fn init(ruby: &Ruby) -> Result<(), Error> { engine_class.define_method("eval_bool_query", method!(Engine::eval_bool_query, 1))?; engine_class.define_method("eval_allow_query", method!(Engine::eval_allow_query, 1))?; engine_class.define_method("eval_deny_query", method!(Engine::eval_deny_query, 1))?; + + // coverage operations + engine_class.define_method( + "set_enable_coverage", + method!(Engine::set_enable_coverage, 1), + )?; + engine_class.define_method( + "get_coverage_report_as_json", + method!(Engine::get_coverage_report_as_json, 0), + )?; + engine_class.define_method( + "get_coverage_report_pretty", + method!(Engine::get_coverage_report_pretty, 0), + )?; + engine_class.define_method( + "clear_coverage_data", + method!(Engine::clear_coverage_data, 0), + )?; + + // print statements + engine_class.define_method("set_gather_prints", method!(Engine::set_gather_prints, 1))?; + engine_class.define_method("take_prints", method!(Engine::take_prints, 0))?; + Ok(()) } diff --git a/bindings/ruby/lib/regorus/version.rb b/bindings/ruby/lib/regorus/version.rb index 4e639ff..72f7a28 100644 --- a/bindings/ruby/lib/regorus/version.rb +++ b/bindings/ruby/lib/regorus/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Regorus - VERSION = "0.1.0" + VERSION = "0.1.5" end diff --git a/bindings/ruby/test/test_regorus.rb b/bindings/ruby/test/test_regorus.rb index 476299b..30ba3c7 100644 --- a/bindings/ruby/test/test_regorus.rb +++ b/bindings/ruby/test/test_regorus.rb @@ -156,6 +156,33 @@ class TestRegorus < Minitest::Test refute_same @engine, cloned_engine end + def test_coverage_printing_json + @engine.set_input(input_for(ALICE)) + @engine.set_enable_coverage(true) + @engine.eval_rule("data.regorus_test.is_employee") + + assert_match(/covered":\[7\],"not_covered":\[3,11,12,15,19\]/, @engine.get_coverage_report_as_json) + end + + def test_coverage_printing_pretty + @engine.set_input(input_for(ALICE)) + @engine.set_enable_coverage(true) + @engine.eval_rule("data.regorus_test.is_employee") + + # to see the colors in the ruby terminal, use `puts @engine.get_coverage_report`` + pretty_coverage_report = @engine.get_coverage_report_pretty + + assert_match(/\e\[31m 3 input.name == data.managers\[_\]/, pretty_coverage_report) + assert_match(/\e\[32m 7 input.name == data.employees\[_\]/, pretty_coverage_report) + end + + def test_gather_print_statements + @engine.set_gather_prints(true) + @engine.eval_query('print("Hello")') + + assert_equal [":1: Hello"], @engine.take_prints + end + def alice_results { result: [