Skip to content

Commit 8f64bac

Browse files
committed
include membrane specs
1 parent 4336213 commit 8f64bac

16 files changed

Lines changed: 904 additions & 5 deletions

lib/membrane/README.md

Lines changed: 120 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,22 @@ Applied to all 15 Ruby files to bring 2014 code to 2025 standards.
177177
```
178178
- **Note:** `strict_checking` was already a keyword arg, kept mixed style for compatibility
179179

180+
#### 5.4 Ruby 3.3 Set API Compatibility
181+
- **Files:** `schemas/record.rb` (1 occurrence, line 50)
182+
- **Change:** `@optional_keys.exclude?(k)``!@optional_keys.include?(k)`
183+
- **Reason:** `Set#exclude?` was removed in Ruby 3.3
184+
- **Impact:** Logically identical, both check if key is NOT in the optional_keys set
185+
- **Example:**
186+
```ruby
187+
# Before:
188+
elsif @optional_keys.exclude?(k)
189+
key_errors[k] = 'Missing key'
190+
191+
# After:
192+
elsif !@optional_keys.include?(k)
193+
key_errors[k] = 'Missing key'
194+
```
195+
180196
### 6. Files NOT Modified
181197

182198
These files were copied verbatim with ONLY the `frozen_string_literal: true` magic comment added:
@@ -194,9 +210,10 @@ These files were copied verbatim with ONLY the `frozen_string_literal: true` mag
194210
| frozen_string_literal added | 15 | +30 | No |
195211
| Modernized raise statements | 10 | ~18 | No |
196212
| Removed .freeze on literals | 1 | ~1 | No |
213+
| Ruby 3.3 Set API fix | 1 | ~1 | No |
197214
| RuboCop compliance | 1 | ~10 | No |
198215
| Code style improvements | 8 | ~20 | No |
199-
| **Total** | **15 files** | **~87 lines** | **No** |
216+
| **Total** | **15 files** | **~88 lines** | **No** |
200217

201218
## Functional Impact
202219

@@ -208,17 +225,116 @@ These files were copied verbatim with ONLY the `frozen_string_literal: true` mag
208225

209226
## Testing
210227

211-
All changes have been verified with:
228+
### Test Coverage
229+
230+
All changes have been verified with comprehensive test coverage:
231+
232+
#### Unit Tests (13 spec files copied from upstream)
233+
234+
**Location:** `spec/unit/lib/membrane/`
235+
236+
**Main Integration Tests:**
237+
- `complex_schema_spec.rb` - Tests complex nested schemas
238+
- `schema_parser_spec.rb` - Tests SchemaParser parsing and deparsing
239+
240+
**Schema Type Tests (11 files):**
241+
- `schemas/any_spec.rb` - Tests Any schema
242+
- `schemas/base_spec.rb` - Tests Base schema
243+
- `schemas/bool_spec.rb` - Tests Bool schema
244+
- `schemas/class_spec.rb` - Tests Class schema
245+
- `schemas/dictionary_spec.rb` - Tests Dictionary schema
246+
- `schemas/enum_spec.rb` - Tests Enum schema
247+
- `schemas/list_spec.rb` - Tests List schema
248+
- `schemas/record_spec.rb` - Tests Record schema
249+
- `schemas/regexp_spec.rb` - Tests Regexp schema
250+
- `schemas/tuple_spec.rb` - Tests Tuple schema
251+
- `schemas/value_spec.rb` - Tests Value schema
252+
253+
**Test Helper:**
254+
- `membrane_spec_helper.rb` - Lightweight spec helper that loads only RSpec and Membrane (no database required), includes `MembraneSpecHelpers` module with `expect_validation_failure` helper
255+
256+
**Spec Adaptations:**
257+
All upstream spec files were adapted for CCNG:
258+
1. Added `frozen_string_literal: true` magic comment
259+
2. Created lightweight `membrane_spec_helper.rb` (doesn't require database connection like CCNG's spec_helper)
260+
3. Changed all specs to use `require_relative "membrane_spec_helper"` instead of `require "spec_helper"`
261+
4. Added `require 'membrane'` to load vendored code
262+
5. Converted `describe``RSpec.describe` (modern RSpec syntax)
263+
6. Converted old RSpec 2.x syntax to RSpec 3.x (~51 occurrences):
264+
- `.should eq``expect().to eq`
265+
- `.should be_nil``expect().to be_nil`
266+
- `.should match``expect().to match`
267+
- `.should_receive``expect().to receive`
268+
- `.should_not``expect().not_to`
269+
7. Fixed frozen string literal compatibility (3 occurrences in schema_parser_spec.rb):
270+
- Removed `expect(val).to receive(:inspect)` style mocks on frozen objects
271+
- Changed to verify output directly: `expect(parser.deparse(schema)).to eq val.inspect`
272+
- Reason: With `frozen_string_literal: true`, can't define singleton methods on frozen objects
273+
- **Impact:** Tests remain logically identical - same scenarios, same validations, same expected outcomes
274+
8. Fixed Ruby 3.3 compatibility issues in specs:
275+
- Changed `Fixnum``Integer` in expected error messages (Ruby 2.4+ unified Fixnum/Bignum into Integer)
276+
- Changed `Record.new({...}, [], true)``Record.new({...}, [], strict_checking: true)` to use keyword argument
277+
9. Fixed RSpec warning about unspecified error matcher (1 occurrence in base_spec.rb):
278+
- Changed `expect { }.to raise_error``expect { }.to raise_error(ArgumentError, /wrong number of arguments/)`
279+
- Reason: Prevents false positives by specifying exact error type and message pattern
280+
10. Added `MembraneSpecHelpers` module to `membrane_spec_helper.rb` with `expect_validation_failure` helper method used 17 times across specs
281+
282+
#### Verification Tests (1 spec file)
283+
284+
**Location:** `spec/unit/lib/`
285+
286+
- `vendored_membrane_spec.rb` - Verifies vendored Membrane loads correctly and provides expected API
287+
288+
#### Manual Testing
289+
212290
- Standalone Ruby tests (all schema types)
213-
- CCNG's vendored_membrane_spec.rb
214291
- Manual validation of error handling
215292
- Verification that all 11 schema types instantiate correctly
293+
- Integration testing with existing CCNG code (VCAP::Config, JsonMessage)
294+
295+
### Running Tests
296+
297+
```bash
298+
# Run all Membrane specs
299+
bundle exec rspec spec/unit/lib/membrane/
300+
301+
# Run specific schema tests
302+
bundle exec rspec spec/unit/lib/membrane/schemas/
303+
304+
# Run integration tests
305+
bundle exec rspec spec/unit/lib/membrane/complex_schema_spec.rb
306+
307+
# Run vendoring verification
308+
bundle exec rspec spec/unit/lib/vendored_membrane_spec.rb
309+
```
310+
311+
## Files Added to CCNG
312+
313+
### Library Code (18 files)
314+
- `lib/membrane.rb` - Shim entrypoint
315+
- `lib/membrane/*.rb` - 4 core files (errors, schemas, schema_parser, version)
316+
- `lib/membrane/schemas/*.rb` - 11 schema type files
317+
- `lib/membrane/LICENSE` - Apache 2.0 license (verbatim copy)
318+
- `lib/membrane/NOTICE` - Copyright notice (verbatim copy)
319+
- `lib/membrane/README.md` - This file (comprehensive documentation)
320+
321+
### Test Files (14 files)
322+
- `spec/unit/lib/membrane/*.rb` - 2 main spec files
323+
- `spec/unit/lib/membrane/schemas/*.rb` - 11 schema spec files
324+
- `spec/unit/lib/membrane/membrane_spec_helper.rb` - Lightweight spec helper (no database)
325+
- `spec/unit/lib/vendored_membrane_spec.rb` - Vendoring verification spec
326+
327+
**Total: 32 files added**
216328

217329
## Maintenance Notes
218330

219331
Since the upstream repository has been inactive since 2014 and is effectively abandoned, these modifications bring the code to modern Ruby 3.3+ standards while maintaining full compatibility. All changes are purely stylistic, performance-related, or code quality improvements - no logic or behavior has been altered.
220332

333+
The comprehensive test suite (13 spec files from upstream + 1 integration spec) ensures that all functionality continues to work correctly and provides confidence for future modifications.
334+
221335
For any questions about these modifications, refer to the git history of:
222-
- `/Users/I546390/SAPDevelop/membrane_inline/cloud_controller_ng/lib/membrane/`
336+
- `cloud_controller_ng/lib/membrane/`
337+
- `cloud_controller_ng/spec/unit/lib/membrane/`
338+
- `cloud_controller_ng/spec/support/membrane_helpers.rb`
223339

224340
Last updated: 2026-03-03

lib/membrane/schemas/record.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def validate
4747
rescue Membrane::SchemaValidationError => e
4848
key_errors[k] = e.to_s
4949
end
50-
elsif @optional_keys.exclude?(k)
50+
elsif !@optional_keys.member?(k)
5151
key_errors[k] = 'Missing key'
5252
end
5353
end
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "membrane_spec_helper"
4+
require "membrane"
5+
6+
RSpec.describe Membrane do
7+
let(:schema) do
8+
Membrane::SchemaParser.parse do
9+
{ "ints" => [Integer],
10+
"tf" => bool,
11+
"any" => any,
12+
"1_or_2" => enum(1, 2),
13+
"str_to_str_to_int" => dict(String, dict(String, Integer)),
14+
optional("optional") => bool,
15+
}
16+
end
17+
end
18+
19+
let(:valid) do
20+
{ "ints" => [1, 2],
21+
"tf" => false,
22+
"any" => nil,
23+
"1_or_2" => 2,
24+
"optional" => true,
25+
"str_to_str_to_int" => { "ten" => { "twenty" => 20 } },
26+
}
27+
end
28+
29+
it "should work with complex nested schemas" do
30+
expect(schema.validate(valid)).to be_nil
31+
end
32+
33+
it "should complain about missing keys" do
34+
required_keys = schema.schemas.keys.dup
35+
required_keys.delete("optional")
36+
37+
required_keys.each do |k|
38+
invalid = valid.dup
39+
40+
invalid.delete(k)
41+
42+
expect_validation_failure(schema, invalid, /#{k} => Missing key/)
43+
end
44+
end
45+
46+
it "should validate nested maps" do
47+
invalid = valid.dup
48+
49+
invalid["str_to_str_to_int"]["ten"]["twenty"] = "invalid"
50+
51+
expect_validation_failure(schema, invalid, /twenty => Expected/)
52+
end
53+
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
# Lightweight spec helper for Membrane specs
4+
# These specs don't need database connection or full CCNG environment
5+
6+
require 'rspec'
7+
8+
# Load the vendored membrane library
9+
require 'membrane'
10+
11+
# Helper methods for Membrane specs
12+
module MembraneSpecHelpers
13+
def expect_validation_failure(schema, object, regex)
14+
expect do
15+
schema.validate(object)
16+
end.to raise_error(Membrane::SchemaValidationError, regex)
17+
end
18+
end
19+
20+
RSpec.configure do |config|
21+
config.include MembraneSpecHelpers
22+
23+
# Standard RSpec configuration
24+
config.expect_with :rspec do |expectations|
25+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
26+
end
27+
28+
config.mock_with :rspec do |mocks|
29+
mocks.verify_partial_doubles = true
30+
end
31+
32+
config.shared_context_metadata_behavior = :apply_to_host_groups
33+
config.filter_run_when_matching :focus
34+
config.example_status_persistence_file_path = 'spec/examples.txt'
35+
config.disable_monkey_patching!
36+
config.warnings = false
37+
38+
config.default_formatter = 'doc' if config.files_to_run.one?
39+
40+
config.order = :random
41+
Kernel.srand config.seed
42+
end

0 commit comments

Comments
 (0)