crispr 0.1.0 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 321944f554596b5fd91d57f1e86190394c64d6d46d5108a13d587a60798902ab
4
- data.tar.gz: f20d189e725811d51b849714654c89e3d36fc553bfb80723208a0baf2d3a545b
3
+ metadata.gz: 0e22eb1dbacaba9bb6d1e3cb3397f53f1d38eb8c4fec6b8f9296faafb17f1bec
4
+ data.tar.gz: 650c04d67c82db6c211a98da8d8e0cfcd01d6b8c442f3425fd0bd34814dd8098
5
5
  SHA512:
6
- metadata.gz: 74b9b78ef2c606dbaecaa0459fc21f98b25c5ec9b47ea930d6f8dd3b3638e81e3f7534f899fcf971138f349e592bef98c72bdbd497a5919de42e66887e9e9f08
7
- data.tar.gz: d3c74eee1b0533eb806141b69e2d8c58b66fac2ab5aea1fc3a98a7835d5c1c603cf42d5e2825d458ee622335cd2fe949a25ad137eae6268472d4233dfee434d6
6
+ metadata.gz: 88583c8997c5c85c7d57fe26c779cd6f7fb86fd96c1559cf97174539f8d0c15d1baa58134752ad3f26d469bfc1cb2d7390dbfb1bd46876e95d6709b286db5fc7
7
+ data.tar.gz: df10e617deb154c9568707a4d2649213d3a82ff0244b26c1d61e7409843155e4c668f8462209dcfffc719f6c7c80187713f789d0dce0cc97e41aabe1ea5b7c03
data/.rubocop.yml CHANGED
@@ -1,6 +1,20 @@
1
+ plugins:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
1
5
  AllCops:
6
+ NewCops: enable
2
7
  TargetRubyVersion: 3.1
3
8
 
9
+ Metrics/AbcSize:
10
+ Max: 30
11
+
12
+ Metrics/MethodLength:
13
+ Max: 100
14
+
15
+ RSpec/ExampleLength:
16
+ Max: 20
17
+
4
18
  Style/StringLiterals:
5
19
  EnforcedStyle: double_quotes
6
20
 
data/bin/crispr ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "crispr"
5
+
6
+ Crispr::CLI.run
data/lib/crispr/cli.rb ADDED
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "crispr/mutator"
4
+ require "crispr/runner"
5
+
6
+ module Crispr
7
+ # Provides the command-line interface for the Crispr gem.
8
+ # Handles argument parsing and invokes the mutation and runner logic.
9
+ class CLI
10
+ def self.run(argv = ARGV)
11
+ command = argv.shift
12
+ case command
13
+ when "run"
14
+ path = argv.shift
15
+ unless path && File.exist?(path)
16
+ puts "Error: Please specify a valid Ruby file to mutate."
17
+ exit 1
18
+ end
19
+
20
+ source = File.read(path)
21
+ mutator = Crispr::Mutator.new(source)
22
+ mutations = mutator.mutations
23
+
24
+ if mutations.empty?
25
+ puts "No mutations found."
26
+ exit 0
27
+ end
28
+
29
+ mutations.each_with_index do |mutated, index|
30
+ puts "Running mutation #{index + 1}/#{mutations.size}..."
31
+ killed = Crispr::Runner.run_mutation(path: path, mutated_source: mutated)
32
+ puts killed ? "💥 Mutation killed" : "⚠️ Mutation survived"
33
+ end
34
+ else
35
+ puts "Usage: crispr run path/to/file.rb"
36
+ exit 1
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ # rubocop:disable Lint/BooleanSymbol
2
+ # frozen_string_literal: true
3
+
4
+ module Crispr
5
+ module Mutations
6
+ # Provides boolean-specific AST mutations.
7
+ # Currently supports toggling `true` to `false` and `false` to `true`.
8
+ module BooleanMutations
9
+ # Returns a list of stringified mutated forms for the given boolean AST node.
10
+ #
11
+ # @param node [Parser::AST::Node] the AST node to inspect
12
+ # @return [Array<String>] mutated Ruby source code strings
13
+ def self.mutations_for(node)
14
+ return [] unless node.is_a?(Parser::AST::Node)
15
+
16
+ case node.type
17
+ when :true
18
+ [Unparser.unparse(Parser::AST::Node.new(:false))]
19
+ when :false
20
+ [Unparser.unparse(Parser::AST::Node.new(:true))]
21
+ else
22
+ []
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ # rubocop:enable Lint/BooleanSymbol
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parser/current"
4
+ require "unparser"
5
+ require_relative "mutations/boolean_mutations"
6
+
7
+ module Crispr
8
+ # Mutator performs simple AST mutations on Ruby source code.
9
+ # Currently, it supports changing `true` literals to `false` and vice versa.
10
+ class Mutator
11
+ def initialize(source_code)
12
+ @source_code = source_code
13
+ end
14
+
15
+ def mutations
16
+ ast = Parser::CurrentRuby.parse(@source_code)
17
+ return [] unless ast
18
+
19
+ find_mutations(ast)
20
+ end
21
+
22
+ private
23
+
24
+ def find_mutations(node)
25
+ return [] unless node.is_a?(Parser::AST::Node)
26
+
27
+ local_mutations = Crispr::Mutations::BooleanMutations.mutations_for(node)
28
+ child_mutations = node.children.flat_map { |child| find_mutations(child) }
29
+
30
+ local_mutations + child_mutations
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module Crispr
6
+ # Runner is responsible for executing tests against mutated code.
7
+ # It temporarily replaces the file's source with a mutated version,
8
+ # runs the test suite, and restores the original file afterward.
9
+ class Runner
10
+ # Runs the test suite with the mutated source code for the given file path.
11
+ #
12
+ # @param path [String] the path to the source file to mutate
13
+ # @param mutated_source [String] the mutated version of the file's source code
14
+ # @return [Boolean] true if the mutation was killed (test suite failed), false otherwise
15
+ def self.run_mutation(path:, mutated_source:)
16
+ original_source = File.read(path)
17
+
18
+ begin
19
+ File.write(path, mutated_source)
20
+
21
+ stdout, stderr, status = Open3.capture3("bundle exec rspec")
22
+ killed = !status.success?
23
+
24
+ puts stdout unless status.success?
25
+ puts stderr unless status.success?
26
+
27
+ killed
28
+ ensure
29
+ File.write(path, original_source)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Crispr
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/crispr.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "crispr/version"
4
+ require_relative "crispr/mutator"
5
+ require_relative "crispr/runner"
6
+ require_relative "crispr/cli"
4
7
 
5
8
  module Crispr
6
9
  class Error < StandardError; end
metadata CHANGED
@@ -1,19 +1,48 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crispr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron F Stanton
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies: []
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: parser
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: unparser
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
12
40
  description: Crispr is a mutation testing tool for Ruby that introduces small code
13
41
  mutations to verify the effectiveness of your test suite.
14
42
  email:
15
43
  - afstanton@gmail.com
16
- executables: []
44
+ executables:
45
+ - crispr
17
46
  extensions: []
18
47
  extra_rdoc_files: []
19
48
  files:
@@ -22,7 +51,12 @@ files:
22
51
  - LICENSE.txt
23
52
  - README.md
24
53
  - Rakefile
54
+ - bin/crispr
25
55
  - lib/crispr.rb
56
+ - lib/crispr/cli.rb
57
+ - lib/crispr/mutations/boolean_mutations.rb
58
+ - lib/crispr/mutator.rb
59
+ - lib/crispr/runner.rb
26
60
  - lib/crispr/version.rb
27
61
  - sig/crispr.rbs
28
62
  homepage: https://github.com/afstanton/crispr
@@ -33,6 +67,7 @@ metadata:
33
67
  homepage_uri: https://github.com/afstanton/crispr
34
68
  source_code_uri: https://github.com/afstanton/crispr
35
69
  changelog_uri: https://github.com/afstanton/crispr/blob/main/CHANGELOG.md
70
+ rubygems_mfa_required: 'true'
36
71
  rdoc_options: []
37
72
  require_paths:
38
73
  - lib