sus 0.33.1 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/context/{usage.md → getting-started.md} +58 -37
  4. data/context/index.yaml +22 -0
  5. data/context/mocking.md +100 -30
  6. data/context/{shared.md → shared-contexts.md} +29 -2
  7. data/lib/sus/assertions.rb +93 -20
  8. data/lib/sus/base.rb +13 -1
  9. data/lib/sus/be.rb +84 -0
  10. data/lib/sus/be_truthy.rb +16 -0
  11. data/lib/sus/be_within.rb +25 -0
  12. data/lib/sus/clock.rb +21 -0
  13. data/lib/sus/config.rb +59 -2
  14. data/lib/sus/context.rb +28 -5
  15. data/lib/sus/describe.rb +14 -0
  16. data/lib/sus/expect.rb +23 -0
  17. data/lib/sus/file.rb +38 -0
  18. data/lib/sus/filter.rb +21 -0
  19. data/lib/sus/fixtures/temporary_directory_context.rb +27 -0
  20. data/lib/sus/fixtures.rb +1 -0
  21. data/lib/sus/have/all.rb +8 -0
  22. data/lib/sus/have/any.rb +8 -0
  23. data/lib/sus/have.rb +42 -0
  24. data/lib/sus/have_duration.rb +16 -0
  25. data/lib/sus/identity.rb +44 -1
  26. data/lib/sus/integrations.rb +1 -0
  27. data/lib/sus/it.rb +33 -0
  28. data/lib/sus/it_behaves_like.rb +16 -0
  29. data/lib/sus/let.rb +3 -0
  30. data/lib/sus/mock.rb +53 -15
  31. data/lib/sus/output/backtrace.rb +31 -1
  32. data/lib/sus/output/bar.rb +17 -0
  33. data/lib/sus/output/buffered.rb +32 -1
  34. data/lib/sus/output/lines.rb +10 -0
  35. data/lib/sus/output/messages.rb +28 -5
  36. data/lib/sus/output/null.rb +18 -4
  37. data/lib/sus/output/progress.rb +29 -1
  38. data/lib/sus/output/status.rb +13 -0
  39. data/lib/sus/output/structured.rb +14 -1
  40. data/lib/sus/output/text.rb +33 -1
  41. data/lib/sus/output/xterm.rb +11 -1
  42. data/lib/sus/output.rb +9 -0
  43. data/lib/sus/raise_exception.rb +16 -0
  44. data/lib/sus/receive.rb +85 -3
  45. data/lib/sus/registry.rb +20 -1
  46. data/lib/sus/respond_to.rb +30 -3
  47. data/lib/sus/shared.rb +16 -0
  48. data/lib/sus/tree.rb +10 -0
  49. data/lib/sus/version.rb +2 -1
  50. data/lib/sus/with.rb +18 -0
  51. data/readme.md +12 -0
  52. data/releases.md +8 -0
  53. data.tar.gz.sig +0 -0
  54. metadata +6 -4
  55. metadata.gz.sig +0 -0
data/lib/sus/registry.rb CHANGED
@@ -19,25 +19,34 @@ require_relative "include_context"
19
19
  require_relative "let"
20
20
 
21
21
  module Sus
22
+ # Represents a registry of test files and contexts.
22
23
  class Registry
24
+ # The glob pattern used to find Ruby files in directories.
23
25
  DIRECTORY_GLOB = "**/*.rb"
24
26
 
25
- # Create a top level scope with self as the instance:
27
+ # Initialize a new registry.
28
+ # @parameter options [Hash] Options to pass to the base context.
26
29
  def initialize(**options)
27
30
  @base = Sus.base(self, **options)
28
31
  @loaded = {}
29
32
  end
30
33
 
34
+ # @attribute [Class] The base test context class.
31
35
  attr :base
32
36
 
37
+ # Print a representation of this registry.
38
+ # @parameter output [Output] The output target.
33
39
  def print(output)
34
40
  output.write("Test Registry")
35
41
  end
36
42
 
43
+ # @returns [String] A string representation of this registry.
37
44
  def to_s
38
45
  @base&.identity&.to_s || self.class.name
39
46
  end
40
47
 
48
+ # Load a test file or directory.
49
+ # @parameter path [String] The path to load (file or directory).
41
50
  def load(path)
42
51
  if ::File.directory?(path)
43
52
  load_directory(path)
@@ -46,24 +55,34 @@ module Sus
46
55
  end
47
56
  end
48
57
 
58
+ # Load a single test file.
59
+ # @parameter path [String] The path to the test file.
49
60
  private def load_file(path)
50
61
  @loaded[path] ||= @base.file(path)
51
62
  end
52
63
 
64
+ # Load all Ruby files in a directory.
65
+ # @parameter path [String] The directory path.
53
66
  private def load_directory(path)
54
67
  ::Dir.glob(::File.join(path, DIRECTORY_GLOB), &self.method(:load_file))
55
68
  end
56
69
 
70
+ # Execute all tests in the registry.
71
+ # @parameter assertions [Assertions] Optional assertions instance to use.
72
+ # @returns [Assertions] The assertions instance with results.
57
73
  def call(assertions = Assertions.default)
58
74
  @base.call(assertions)
59
75
 
60
76
  return assertions
61
77
  end
62
78
 
79
+ # Iterate over all test cases in the registry.
80
+ # @yields {|test| ...} Each test case.
63
81
  def each(...)
64
82
  @base.each(...)
65
83
  end
66
84
 
85
+ # @returns [Hash] The child contexts and tests.
67
86
  def children
68
87
  @base.children
69
88
  end
@@ -1,16 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022, by Samuel Williams.
4
+ # Copyright, 2022-2025, by Samuel Williams.
5
5
 
6
6
  module Sus
7
+ # Represents a predicate that checks if an object responds to a method.
7
8
  class RespondTo
9
+ # Represents a constraint on method parameters.
8
10
  class WithParameters
9
- # @parameter [Array(Symbol)] List of method parameters in the expected order, must include at least all required parameters but can also list optional parameters.
11
+ # Initialize a new WithParameters constraint.
12
+ # @parameter parameters [Array(Symbol)] List of method parameters in the expected order, must include at least all required parameters but can also list optional parameters.
10
13
  def initialize(parameters)
11
14
  @parameters = parameters
12
15
  end
13
16
 
17
+ # Evaluate this constraint against method parameters.
18
+ # @parameter assertions [Assertions] The assertions instance to use.
19
+ # @parameter subject [Array] The method parameters to check.
14
20
  def call(assertions, subject)
15
21
  parameters = @parameters.dup
16
22
 
@@ -32,15 +38,23 @@ module Sus
32
38
  end
33
39
  end
34
40
 
41
+ # Represents a constraint on method keyword options.
35
42
  class WithOptions
43
+ # Initialize a new WithOptions constraint.
44
+ # @parameter options [Array(Symbol)] The option names that should be present.
36
45
  def initialize(options)
37
46
  @options = options
38
47
  end
39
-
48
+
49
+ # Print a representation of this constraint.
50
+ # @parameter output [Output] The output target.
40
51
  def print(output)
41
52
  output.write("with options ", :variable, @options.inspect)
42
53
  end
43
54
 
55
+ # Evaluate this constraint against method parameters.
56
+ # @parameter assertions [Assertions] The assertions instance to use.
57
+ # @parameter subject [Array] The method parameters to check.
44
58
  def call(assertions, subject)
45
59
  options = {}
46
60
  @options.each{|name| options[name] = nil}
@@ -57,21 +71,31 @@ module Sus
57
71
  end
58
72
  end
59
73
 
74
+ # Initialize a new RespondTo predicate.
75
+ # @parameter method [Symbol, String] The method name to check for.
60
76
  def initialize(method)
61
77
  @method = method
62
78
  @parameters = nil
63
79
  @options = nil
64
80
  end
65
81
 
82
+ # Specify that the method should have specific keyword options.
83
+ # @parameter options [Array(Symbol)] The option names that should be present.
84
+ # @returns [RespondTo] Returns self for method chaining.
66
85
  def with_options(*options)
67
86
  @options = WithOptions.new(options)
68
87
  return self
69
88
  end
70
89
 
90
+ # Print a representation of this predicate.
91
+ # @parameter output [Output] The output target.
71
92
  def print(output)
72
93
  output.write("respond to ", :variable, @method.to_s, :reset)
73
94
  end
74
95
 
96
+ # Evaluate this predicate against a subject.
97
+ # @parameter assertions [Assertions] The assertions instance to use.
98
+ # @parameter subject [Object] The subject to evaluate.
75
99
  def call(assertions, subject)
76
100
  assertions.nested(self) do |assertions|
77
101
  condition = subject.respond_to?(@method)
@@ -87,6 +111,9 @@ module Sus
87
111
  end
88
112
 
89
113
  class Base
114
+ # Create a predicate that checks if the subject responds to a method.
115
+ # @parameter method [Symbol, String] The method name to check for.
116
+ # @returns [RespondTo] A new RespondTo predicate.
90
117
  def respond_to(method)
91
118
  RespondTo.new(method)
92
119
  end
data/lib/sus/shared.rb CHANGED
@@ -6,10 +6,18 @@
6
6
  require_relative "context"
7
7
 
8
8
  module Sus
9
+ # Represents a shared test context that can be reused across multiple test files.
9
10
  module Shared
11
+ # @attribute [String] The name of the shared context.
10
12
  attr_accessor :name
13
+
14
+ # @attribute [Proc] The block containing the shared test code.
11
15
  attr_accessor :block
12
16
 
17
+ # Build a new Shared context.
18
+ # @parameter name [String] The name of the shared context.
19
+ # @parameter block [Proc] The block containing the shared test code.
20
+ # @returns [Module] A new Shared module.
13
21
  def self.build(name, block)
14
22
  base = Module.new
15
23
  base.extend(Shared)
@@ -19,15 +27,23 @@ module Sus
19
27
  return base
20
28
  end
21
29
 
30
+ # Called when this module is included in a test class.
31
+ # @parameter base [Class] The class including this module.
22
32
  def included(base)
23
33
  base.class_exec(&self.block)
24
34
  end
25
35
 
36
+ # Called when this module is prepended to a test class.
37
+ # @parameter base [Class] The class prepending this module.
26
38
  def prepended(base)
27
39
  base.class_exec(&self.block)
28
40
  end
29
41
  end
30
42
 
43
+ # Create a new shared test context.
44
+ # @parameter name [String] The name of the shared context.
45
+ # @yields {...} The block containing the shared test code.
46
+ # @returns [Shared] A new Shared module.
31
47
  def self.Shared(name, &block)
32
48
  Shared.build(name, block)
33
49
  end
data/lib/sus/tree.rb CHANGED
@@ -4,11 +4,18 @@
4
4
  # Copyright, 2023, by Samuel Williams.
5
5
 
6
6
  module Sus
7
+ # Represents a tree structure of test contexts.
7
8
  class Tree
9
+ # Initialize a new Tree.
10
+ # @parameter context [Object] The root context.
8
11
  def initialize(context)
9
12
  @context = context
10
13
  end
11
14
 
15
+ # Traverse the tree, yielding each context.
16
+ # @parameter current [Object] The current context (defaults to root).
17
+ # @yields {|context| ...} Each context in the tree.
18
+ # @returns [Hash] A hash representation of the tree.
12
19
  def traverse(current = @context, &block)
13
20
  node = {}
14
21
 
@@ -23,6 +30,9 @@ module Sus
23
30
  return node
24
31
  end
25
32
 
33
+ # Convert the tree to JSON.
34
+ # @parameter options [Hash, nil] Options to pass to JSON.generate.
35
+ # @returns [String] A JSON representation of the tree.
26
36
  def to_json(options = nil)
27
37
  traverse do |context|
28
38
  [context.identity.to_s, context.description.to_s, context.leaf?]
data/lib/sus/version.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
+ # @namespace
6
7
  module Sus
7
- VERSION = "0.33.1"
8
+ VERSION = "0.35.0"
8
9
  end
data/lib/sus/with.rb CHANGED
@@ -6,12 +6,23 @@
6
6
  require_relative "context"
7
7
 
8
8
  module Sus
9
+ # Represents a test context with specific conditions or variables.
9
10
  module With
10
11
  extend Context
11
12
 
13
+ # @attribute [String] The subject description of this context.
12
14
  attr_accessor :subject
15
+
16
+ # @attribute [Hash] The variables available in this context.
13
17
  attr_accessor :variables
14
18
 
19
+ # Build a new with block class.
20
+ # @parameter parent [Class] The parent context class.
21
+ # @parameter subject [String] The subject description.
22
+ # @parameter variables [Hash] Variables to make available in the context.
23
+ # @parameter unique [Boolean] Whether the identity should be unique.
24
+ # @yields {...} Optional block containing nested tests.
25
+ # @returns [Class] A new with block class.
15
26
  def self.build(parent, subject, variables, unique: true, &block)
16
27
  base = Class.new(parent)
17
28
  base.singleton_class.prepend(With)
@@ -36,6 +47,8 @@ module Sus
36
47
  return base
37
48
  end
38
49
 
50
+ # Print a representation of this with block.
51
+ # @parameter output [Output] The output target.
39
52
  def print(output)
40
53
  self.superclass.print(output)
41
54
 
@@ -47,6 +60,11 @@ module Sus
47
60
  end
48
61
 
49
62
  module Context
63
+ # Define a new test context with specific conditions or variables.
64
+ # @parameter subject [String | Nil] Optional subject description. If nil, uses variables.inspect.
65
+ # @parameter unique [Boolean] Whether the identity should be unique.
66
+ # @parameter variables [Hash] Variables to make available in the context.
67
+ # @yields {...} Optional block containing nested tests.
50
68
  def with(subject = nil, unique: true, **variables, &block)
51
69
  subject ||= variables.inspect
52
70
 
data/readme.md CHANGED
@@ -25,10 +25,22 @@ Please see the [project documentation](https://socketry.github.io/sus/) for more
25
25
 
26
26
  - [Getting Started](https://socketry.github.io/sus/guides/getting-started/index) - This guide explains how to use the `sus` gem to write tests for your Ruby projects.
27
27
 
28
+ - [Mocking](https://socketry.github.io/sus/guides/mocking/index) - This guide explains how to use mocking in sus to isolate dependencies and verify interactions in your tests.
29
+
30
+ - [Shared Test Behaviors and Fixtures](https://socketry.github.io/sus/guides/shared-contexts/index) - This guide explains how to use shared test contexts and fixtures in sus to reduce duplication and ensure consistent test behavior across your test suite.
31
+
28
32
  ## Releases
29
33
 
30
34
  Please see the [project releases](https://socketry.github.io/sus/releases/index) for all releases.
31
35
 
36
+ ### v0.35.0
37
+
38
+ - Add `Sus::Fixtures::TemporaryDirectoryContext`.
39
+
40
+ ### v0.34.0
41
+
42
+ - Allow `expect(...).to receive(...)` to accept one or more calls (at least once).
43
+
32
44
  ### v0.33.0
33
45
 
34
46
  - Add support for `agent-context` gem.
data/releases.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Releases
2
2
 
3
+ ## v0.35.0
4
+
5
+ - Add `Sus::Fixtures::TemporaryDirectoryContext`.
6
+
7
+ ## v0.34.0
8
+
9
+ - Allow `expect(...).to receive(...)` to accept one or more calls (at least once).
10
+
3
11
  ## v0.33.0
4
12
 
5
13
  - Add support for `agent-context` gem.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.33.1
4
+ version: 0.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -51,9 +51,10 @@ files:
51
51
  - bin/sus-host
52
52
  - bin/sus-parallel
53
53
  - bin/sus-tree
54
+ - context/getting-started.md
55
+ - context/index.yaml
54
56
  - context/mocking.md
55
- - context/shared.md
56
- - context/usage.md
57
+ - context/shared-contexts.md
57
58
  - lib/sus.rb
58
59
  - lib/sus/assertions.rb
59
60
  - lib/sus/base.rb
@@ -68,6 +69,7 @@ files:
68
69
  - lib/sus/file.rb
69
70
  - lib/sus/filter.rb
70
71
  - lib/sus/fixtures.rb
72
+ - lib/sus/fixtures/temporary_directory_context.rb
71
73
  - lib/sus/have.rb
72
74
  - lib/sus/have/all.rb
73
75
  - lib/sus/have/any.rb
@@ -123,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
125
  - !ruby/object:Gem::Version
124
126
  version: '0'
125
127
  requirements: []
126
- rubygems_version: 3.6.7
128
+ rubygems_version: 3.6.9
127
129
  specification_version: 4
128
130
  summary: A fast and scalable test runner.
129
131
  test_files: []
metadata.gz.sig CHANGED
Binary file