bddgenx 0.1.10 → 0.1.11

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: 412eee7cb6c56d539e31e45baeebccf7db3746d9e6ac440bafbe7cdbf4050c2c
4
- data.tar.gz: 6c0dba41550f7965567c503987c7a73dc52ead909bc65950b776fc34a2b6d11d
3
+ metadata.gz: af60771edb97be73190b73c21b31b4eee47b165b9d8d7532d3edb9416c7518d6
4
+ data.tar.gz: 62b5ceee7e6b0eb13788accf3029bb3d03209b0b7570a8d8dc2f88c3c833c311
5
5
  SHA512:
6
- metadata.gz: 64a9b9ed93fccccf3ee74c16e9bcb7da5a3a478b16801306d04ef841b519cf82481a22a4d85de8700e48977ee3348a7999bd344545740b9363917740c40e539c
7
- data.tar.gz: db405418d2c50e990e3904cb7bc527109ff7e8f3647dcf3cd758ff240f43d0c5dbdbc36abbd17929bb893a375a42a6eb6dda67b2d08709ca000d93105d727f23
6
+ metadata.gz: 952f0c4f63dbffa3bf27ae47916a2eac46584ae3cb644237cea75c2397d7f5a22e534a5a8b7a8cc0367e30b76e70673f382027d16fc8b593356b84064e25f5dd
7
+ data.tar.gz: 3360a6b972cf82d6891c9c323d2ccc5f1dc05298cd3ee771e0e891fd02c3559391dcfc4e1d84b9070d993be0144e86447f4bfae905bd09705c6149153189f16b
@@ -1,16 +1,18 @@
1
1
  require 'fileutils'
2
2
  require 'time'
3
3
 
4
- module Backup
5
- def self.salvar_versao_antiga(caminho)
6
- return unless File.exist?(caminho)
4
+ module Bddgenx
5
+ class Backup
6
+ def self.salvar_versao_antiga(caminho)
7
+ return unless File.exist?(caminho)
7
8
 
8
- FileUtils.mkdir_p("backup")
9
- base = File.basename(caminho, ".feature")
10
- timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
11
- destino = "backup/#{base}_#{timestamp}.feature"
9
+ FileUtils.mkdir_p("backup")
10
+ base = File.basename(caminho, ".feature")
11
+ timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
12
+ destino = "backup/#{base}_#{timestamp}.feature"
12
13
 
13
- FileUtils.cp(caminho, destino)
14
- puts "📦 Backup criado: #{destino}"
14
+ FileUtils.cp(caminho, destino)
15
+ puts "📦 Backup criado: #{destino}"
16
+ end
15
17
  end
16
18
  end
data/lib/bddgenx/cli.rb CHANGED
@@ -1,34 +1,36 @@
1
- module CLI
2
- def self.selecionar_arquivos_txt(diretorio)
3
- arquivos = Dir.glob("#{diretorio}/*.txt")
1
+ module Bddgenx
2
+ class Cli
3
+ def self.selecionar_arquivos_txt(diretorio)
4
+ arquivos = Dir.glob("#{diretorio}/*.txt")
4
5
 
5
- if arquivos.empty?
6
- puts "❌ Nenhum arquivo .txt encontrado no diretório '#{diretorio}'"
7
- exit
8
- end
9
-
10
- arquivos
6
+ if arquivos.empty?
7
+ puts "❌ Nenhum arquivo .txt encontrado no diretório '#{diretorio}'"
8
+ exit
9
+ end
11
10
 
12
- puts "📂 Arquivos disponíveis em '#{diretorio}':"
13
- arquivos.each_with_index do |arquivo, i|
14
- puts " #{i + 1}. #{File.basename(arquivo)}"
15
- end
11
+ arquivos
16
12
 
17
- print "\nDigite os números dos arquivos que deseja processar (ex: 1,2,3 ou 'todos'): "
18
- entrada = gets.chomp
13
+ puts "📂 Arquivos disponíveis em '#{diretorio}':"
14
+ arquivos.each_with_index do |arquivo, i|
15
+ puts " #{i + 1}. #{File.basename(arquivo)}"
16
+ end
19
17
 
20
- selecionados = if entrada.downcase == 'todos'
21
- arquivos
22
- else
23
- indices = entrada.split(',').map { |n| n.strip.to_i - 1 }
24
- indices.map { |i| arquivos[i] }.compact
25
- end
18
+ print "\nDigite os números dos arquivos que deseja processar (ex: 1,2,3 ou 'todos'): "
19
+ entrada = gets.chomp
26
20
 
27
- if selecionados.empty?
28
- puts "❌ Nenhum arquivo válido selecionado."
29
- exit
30
- end
21
+ selecionados = if entrada.downcase == 'todos'
22
+ arquivos
23
+ else
24
+ indices = entrada.split(',').map { |n| n.strip.to_i - 1 }
25
+ indices.map { |i| arquivos[i] }.compact
26
+ end
31
27
 
32
- selecionados
28
+ if selecionados.empty?
29
+ puts "❌ Nenhum arquivo válido selecionado."
30
+ exit
31
+ end
32
+
33
+ selecionados
34
+ end
33
35
  end
34
36
  end
@@ -1,150 +1,151 @@
1
1
  require 'fileutils'
2
2
 
3
- module Generator
4
- TIPOS_ISTQB = {
5
- "SUCCESS" => "Teste Positivo",
6
- "FAILURE" => "Teste Negativo",
7
- "ERROR" => "Teste de Erro",
8
- "EXCEPTION" => "Teste de Exceção",
9
- "VALIDATION" => "Teste de Validação",
10
- "PERMISSION" => "Teste de Permissão",
11
- "EDGE_CASE" => "Teste de Limite",
12
- "PERFORMANCE" => "Teste de Desempenho"
13
- }
14
-
15
- TIPOS_CENARIO = %w[
16
- SUCCESS FAILURE ERROR EXCEPTION
17
- VALIDATION PERMISSION EDGE_CASE PERFORMANCE
18
- ]
19
-
20
-
21
- def self.gerar_feature(historia)
22
- idioma = historia[:idioma] || 'pt'
23
-
24
- # Define os conectores de acordo com o idioma
25
- palavras = {
26
- contexto: idioma == 'en' ? 'Background' : 'Contexto',
27
- cenario: idioma == 'en' ? 'Scenario' : 'Cenário',
28
- esquema: idioma == 'en' ? 'Scenario Outline' : 'Esquema do Cenário',
29
- exemplos: idioma == 'en' ? 'Examples' : 'Exemplos',
30
- regra: idioma == 'en' ? 'Rule' : 'Regra'
3
+ module Bddgenx
4
+ class Generator
5
+ TIPOS_ISTQB = {
6
+ "SUCCESS" => "Teste Positivo",
7
+ "FAILURE" => "Teste Negativo",
8
+ "ERROR" => "Teste de Erro",
9
+ "EXCEPTION" => "Teste de Exceção",
10
+ "VALIDATION" => "Teste de Validação",
11
+ "PERMISSION" => "Teste de Permissão",
12
+ "EDGE_CASE" => "Teste de Limite",
13
+ "PERFORMANCE" => "Teste de Desempenho"
31
14
  }
32
15
 
33
- nome_base = historia[:quero].gsub(/[^a-zA-Z0-9]/, '_').downcase
34
- caminho = "features/#{nome_base}.feature"
35
-
36
- conteudo = <<~HEADER
37
- # language: #{idioma}
38
- Funcionalidade: #{historia[:quero].sub(/^Quero/, '').strip}
39
-
40
- #{historia[:como]}
41
- #{historia[:quero]}
42
- #{historia[:para]}
16
+ TIPOS_CENARIO = %w[
17
+ SUCCESS FAILURE ERROR EXCEPTION
18
+ VALIDATION PERMISSION EDGE_CASE PERFORMANCE
19
+ ]
20
+
21
+
22
+ def self.gerar_feature(historia)
23
+ idioma = historia[:idioma] || 'pt'
24
+
25
+ # Define os conectores de acordo com o idioma
26
+ palavras = {
27
+ contexto: idioma == 'en' ? 'Background' : 'Contexto',
28
+ cenario: idioma == 'en' ? 'Scenario' : 'Cenário',
29
+ esquema: idioma == 'en' ? 'Scenario Outline' : 'Esquema do Cenário',
30
+ exemplos: idioma == 'en' ? 'Examples' : 'Exemplos',
31
+ regra: idioma == 'en' ? 'Rule' : 'Regra'
32
+ }
33
+
34
+ nome_base = historia[:quero].gsub(/[^a-zA-Z0-9]/, '_').downcase
35
+ caminho = "features/#{nome_base}.feature"
36
+
37
+ conteudo = <<~HEADER
38
+ # language: #{idioma}
39
+ Funcionalidade: #{historia[:quero].sub(/^Quero/, '').strip}
40
+
41
+ #{historia[:como]}
42
+ #{historia[:quero]}
43
+ #{historia[:para]}
44
+
45
+ HEADER
46
+
47
+ # Regras
48
+ if historia[:regras]&.any?
49
+ conteudo += " #{palavras[:regra]}: #{historia[:regras].first}\n"
50
+ historia[:regras][1..].each do |linha|
51
+ conteudo += " #{linha}\n"
52
+ end
53
+ conteudo += "\n"
54
+ end
43
55
 
44
- HEADER
45
56
 
46
- # Regras
47
- if historia[:regras]&.any?
48
- conteudo += " #{palavras[:regra]}: #{historia[:regras].first}\n"
49
- historia[:regras][1..].each do |linha|
50
- conteudo += " #{linha}\n"
57
+ # Contexto
58
+ if historia[:blocos]["CONTEXT"]&.any?
59
+ conteudo += " #{palavras[:contexto]}:\n"
60
+ historia[:blocos]["CONTEXT"].each { |p| conteudo += " #{p}\n" }
61
+ conteudo += "\n"
51
62
  end
52
- conteudo += "\n"
53
- end
54
63
 
64
+ # Cenários
65
+ TIPOS_CENARIO.each do |tipo|
66
+ passos = historia[:blocos][tipo]
67
+ passos = passos&.reject { |l| l.strip.empty? } || []
68
+ next if passos.empty?
55
69
 
56
- # Contexto
57
- if historia[:blocos]["CONTEXT"]&.any?
58
- conteudo += " #{palavras[:contexto]}:\n"
59
- historia[:blocos]["CONTEXT"].each { |p| conteudo += " #{p}\n" }
60
- conteudo += "\n"
61
- end
70
+ # Ignora geração duplicada se for um SUCCESS parametrizado com EXAMPLES
71
+ if tipo == "SUCCESS" && historia[:blocos]["EXAMPLES"]&.any?
72
+ possui_parametros = passos.any? { |p| p.include?('<') }
73
+ next if possui_parametros
74
+ end
62
75
 
63
- # Cenários
64
- TIPOS_CENARIO.each do |tipo|
65
- passos = historia[:blocos][tipo]
66
- passos = passos&.reject { |l| l.strip.empty? } || []
67
- next if passos.empty?
76
+ nome_teste = TIPOS_ISTQB[tipo] || palavras[:cenario]
77
+ contexto = passos.first&.gsub(/^(Dado que|Given|Quando|When|Então|Then|E|And)/, '')&.strip || "Condição"
78
+ resultado = passos.last&.gsub(/^(Então|Then|E|And)/, '')&.strip || "Resultado"
79
+ nome_cenario = "#{nome_teste} - #{contexto} - #{resultado}"
68
80
 
69
- # Ignora geração duplicada se for um SUCCESS parametrizado com EXAMPLES
70
- if tipo == "SUCCESS" && historia[:blocos]["EXAMPLES"]&.any?
71
- possui_parametros = passos.any? { |p| p.include?('<') }
72
- next if possui_parametros
81
+ conteudo += " @#{tipo.downcase}\n"
82
+ conteudo += " #{palavras[:cenario]}: #{nome_cenario}\n"
83
+ passos.each { |p| conteudo += " #{p}\n" }
84
+ conteudo += "\n"
73
85
  end
74
86
 
75
- nome_teste = TIPOS_ISTQB[tipo] || palavras[:cenario]
76
- contexto = passos.first&.gsub(/^(Dado que|Given|Quando|When|Então|Then|E|And)/, '')&.strip || "Condição"
77
- resultado = passos.last&.gsub(/^(Então|Then|E|And)/, '')&.strip || "Resultado"
78
- nome_cenario = "#{nome_teste} - #{contexto} - #{resultado}"
87
+ # Esquema do Cenário com Exemplos
88
+ if historia[:blocos]["EXAMPLES"]&.any?
89
+ exemplo_bruto = historia[:blocos]["EXAMPLES"]
90
+ grupos = dividir_examples(exemplo_bruto)
79
91
 
80
- conteudo += " @#{tipo.downcase}\n"
81
- conteudo += " #{palavras[:cenario]}: #{nome_cenario}\n"
82
- passos.each { |p| conteudo += " #{p}\n" }
83
- conteudo += "\n"
84
- end
92
+ grupos.each_with_index do |tabela, i|
93
+ cabecalho = tabela.first.gsub('|', '').split.map(&:strip)
94
+ linhas = tabela[1..].map { |linha| linha.split('|').reject(&:empty?).map(&:strip) }
85
95
 
86
- # Esquema do Cenário com Exemplos
87
- if historia[:blocos]["EXAMPLES"]&.any?
88
- exemplo_bruto = historia[:blocos]["EXAMPLES"]
89
- grupos = dividir_examples(exemplo_bruto)
96
+ exemplos = { cabecalho: cabecalho, linhas: linhas }
90
97
 
91
- grupos.each_with_index do |tabela, i|
92
- cabecalho = tabela.first.gsub('|', '').split.map(&:strip)
93
- linhas = tabela[1..].map { |linha| linha.split('|').reject(&:empty?).map(&:strip) }
98
+ passos_outline = historia[:blocos]["SUCCESS"].select do |linha|
99
+ cabecalho.any? { |coluna| linha.include?("<#{coluna}>") }
100
+ end
94
101
 
95
- exemplos = { cabecalho: cabecalho, linhas: linhas }
102
+ next if passos_outline.empty?
96
103
 
97
- passos_outline = historia[:blocos]["SUCCESS"].select do |linha|
98
- cabecalho.any? { |coluna| linha.include?("<#{coluna}>") }
99
- end
104
+ conteudo += "\n"
105
+ conteudo += idioma == 'en' ? " Scenario Outline: Example #{i + 1}\n" : " Esquema do Cenário: Exemplo #{i + 1}\n"
100
106
 
101
- next if passos_outline.empty?
107
+ passos_outline.each do |passo|
108
+ conteudo += " #{passo}\n"
109
+ end
102
110
 
103
- conteudo += "\n"
104
- conteudo += idioma == 'en' ? " Scenario Outline: Example #{i + 1}\n" : " Esquema do Cenário: Exemplo #{i + 1}\n"
105
-
106
- passos_outline.each do |passo|
107
- conteudo += " #{passo}\n"
111
+ conteudo += "\n"
112
+ conteudo += idioma == 'en' ? " Examples:\n" : " Exemplos:\n"
113
+ conteudo += " #{tabela.first}\n"
114
+ tabela[1..].each { |linha| conteudo += " #{linha}\n" }
108
115
  end
109
-
110
- conteudo += "\n"
111
- conteudo += idioma == 'en' ? " Examples:\n" : " Exemplos:\n"
112
- conteudo += " #{tabela.first}\n"
113
- tabela[1..].each { |linha| conteudo += " #{linha}\n" }
114
116
  end
117
+
118
+ [caminho, conteudo]
115
119
  end
116
120
 
117
- [caminho, conteudo]
118
- end
121
+ # Salva o arquivo .feature gerado
122
+ # Retorna true se o arquivo foi salvo com sucesso, false caso contrário
123
+ def self.salvar_feature(caminho, conteudo)
124
+ if conteudo.strip.empty?
125
+ puts "⚠️ Nenhum conteúdo gerado para: #{caminho} (ignorado)"
126
+ return false
127
+ end
119
128
 
120
- # Salva o arquivo .feature gerado
121
- # Retorna true se o arquivo foi salvo com sucesso, false caso contrário
122
- def self.salvar_feature(caminho, conteudo)
123
- if conteudo.strip.empty?
124
- puts "⚠️ Nenhum conteúdo gerado para: #{caminho} (ignorado)"
125
- return false
129
+ File.write(caminho, conteudo)
130
+ puts "✅ Arquivo .feature gerado: #{caminho}"
131
+ true
126
132
  end
127
133
 
128
- File.write(caminho, conteudo)
129
- puts "✅ Arquivo .feature gerado: #{caminho}"
130
- true
131
- end
132
-
133
- def self.dividir_examples(tabela_bruta)
134
- grupos = []
135
- grupo_atual = []
134
+ def self.dividir_examples(tabela_bruta)
135
+ grupos = []
136
+ grupo_atual = []
136
137
 
137
- tabela_bruta.each do |linha|
138
- if linha.strip =~ /^\|\s*[\w\s]+\|/ && grupo_atual.any? && linha.strip == linha.strip.squeeze(" ")
139
- grupos << grupo_atual
140
- grupo_atual = [linha]
141
- else
142
- grupo_atual << linha
138
+ tabela_bruta.each do |linha|
139
+ if linha.strip =~ /^\|\s*[\w\s]+\|/ && grupo_atual.any? && linha.strip == linha.strip.squeeze(" ")
140
+ grupos << grupo_atual
141
+ grupo_atual = [linha]
142
+ else
143
+ grupo_atual << linha
144
+ end
143
145
  end
144
- end
145
146
 
146
- grupos << grupo_atual unless grupo_atual.empty?
147
- grupos
147
+ grupos << grupo_atual unless grupo_atual.empty?
148
+ grupos
149
+ end
148
150
  end
149
-
150
151
  end
@@ -1,162 +1,164 @@
1
1
  require 'fileutils'
2
2
  require_relative 'utils/verificador'
3
3
 
4
- module StepsGenerator
5
- PADROES = {
6
- 'pt' => %w[Dado Quando Então E],
7
- 'en' => %w[Given When Then And]
8
- }
9
-
10
- TIPOS_BLOCOS = %w[
11
- CONTEXT SUCCESS FAILURE ERROR EXCEPTION
12
- VALIDATION PERMISSION EDGE_CASE PERFORMANCE
13
- EXAMPLES REGRA RULE
14
- ]
15
-
16
- def self.gerar_passos(historia, nome_arquivo_feature)
17
- idioma = historia[:idioma] || 'pt'
18
- conectores = PADROES[idioma]
19
- passos_gerados = []
20
-
21
- grupos_examples = dividir_examples(historia[:blocos]["EXAMPLES"]) if historia[:blocos]["EXAMPLES"]&.any?
22
-
23
- TIPOS_BLOCOS.each do |tipo|
24
- blocos = tipo == "REGRA" || tipo == "RULE" ? historia[:regras] : historia[:blocos][tipo]
25
- next unless blocos.is_a?(Array)
26
-
27
- passos = blocos.dup
28
-
29
- passos.each do |linha|
30
- conector = conectores.find { |c| linha.strip.start_with?(c) }
31
- next unless conector
32
-
33
- corpo = linha.strip.sub(/^#{conector}/, '').strip
34
-
35
- # Sanitiza aspas duplas envolvendo parâmetros, ex: "<nome>" -> <nome>
36
- corpo_sanitizado = corpo.gsub(/"(<[^>]+>)"/, '\1')
37
-
38
- # Verifica se este passo pertence a algum grupo de exemplos
39
- grupo_exemplo_compat = nil
40
-
41
- if tipo == "SUCCESS" && grupos_examples
42
- grupos_examples.each do |grupo|
43
- cabecalho = grupo.first.gsub('|', '').split.map(&:strip)
44
- if cabecalho.any? { |col| corpo.include?("<#{col}>") }
45
- grupo_exemplo_compat = {
46
- cabecalho: cabecalho,
47
- linhas: grupo[1..].map { |linha| linha.split('|').reject(&:empty?).map(&:strip) }
48
- }
49
- break
4
+ module Bddgenx
5
+ class StepsGenerator
6
+ PADROES = {
7
+ 'pt' => %w[Dado Quando Então E],
8
+ 'en' => %w[Given When Then And]
9
+ }
10
+
11
+ TIPOS_BLOCOS = %w[
12
+ CONTEXT SUCCESS FAILURE ERROR EXCEPTION
13
+ VALIDATION PERMISSION EDGE_CASE PERFORMANCE
14
+ EXAMPLES REGRA RULE
15
+ ]
16
+
17
+ def self.gerar_passos(historia, nome_arquivo_feature)
18
+ idioma = historia[:idioma] || 'pt'
19
+ conectores = PADROES[idioma]
20
+ passos_gerados = []
21
+
22
+ grupos_examples = dividir_examples(historia[:blocos]["EXAMPLES"]) if historia[:blocos]["EXAMPLES"]&.any?
23
+
24
+ TIPOS_BLOCOS.each do |tipo|
25
+ blocos = tipo == "REGRA" || tipo == "RULE" ? historia[:regras] : historia[:blocos][tipo]
26
+ next unless blocos.is_a?(Array)
27
+
28
+ passos = blocos.dup
29
+
30
+ passos.each do |linha|
31
+ conector = conectores.find { |c| linha.strip.start_with?(c) }
32
+ next unless conector
33
+
34
+ corpo = linha.strip.sub(/^#{conector}/, '').strip
35
+
36
+ # Sanitiza aspas duplas envolvendo parâmetros, ex: "<nome>" -> <nome>
37
+ corpo_sanitizado = corpo.gsub(/"(<[^>]+>)"/, '\1')
38
+
39
+ # Verifica se este passo pertence a algum grupo de exemplos
40
+ grupo_exemplo_compat = nil
41
+
42
+ if tipo == "SUCCESS" && grupos_examples
43
+ grupos_examples.each do |grupo|
44
+ cabecalho = grupo.first.gsub('|', '').split.map(&:strip)
45
+ if cabecalho.any? { |col| corpo.include?("<#{col}>") }
46
+ grupo_exemplo_compat = {
47
+ cabecalho: cabecalho,
48
+ linhas: grupo[1..].map { |linha| linha.split('|').reject(&:empty?).map(&:strip) }
49
+ }
50
+ break
51
+ end
50
52
  end
51
53
  end
52
- end
53
54
 
54
- if grupo_exemplo_compat
55
- # Substitui cada <param> por {tipo} dinamicamente
56
- corpo_parametrizado = corpo_sanitizado.gsub(/<([^>]+)>/) do
57
- nome = $1.strip
58
- tipo_param = detectar_tipo_param(nome, grupo_exemplo_compat)
59
- "{#{tipo_param}}"
55
+ if grupo_exemplo_compat
56
+ # Substitui cada <param> por {tipo} dinamicamente
57
+ corpo_parametrizado = corpo_sanitizado.gsub(/<([^>]+)>/) do
58
+ nome = $1.strip
59
+ tipo_param = detectar_tipo_param(nome, grupo_exemplo_compat)
60
+ "{#{tipo_param}}"
61
+ end
62
+
63
+ parametros = corpo.scan(/<([^>]+)>/).flatten.map { |p| p.strip.gsub(' ', '_') }
64
+ param_list = parametros.join(', ')
65
+ else
66
+ corpo_parametrizado = corpo
67
+ parametros = []
68
+ param_list = ""
60
69
  end
61
70
 
62
- parametros = corpo.scan(/<([^>]+)>/).flatten.map { |p| p.strip.gsub(' ', '_') }
63
- param_list = parametros.join(', ')
64
- else
65
- corpo_parametrizado = corpo
66
- parametros = []
67
- param_list = ""
71
+ passos_gerados << {
72
+ conector: conector,
73
+ raw: corpo,
74
+ param: corpo_parametrizado,
75
+ args: param_list,
76
+ tipo: tipo
77
+ } unless passos_gerados.any? { |p| p[:param] == corpo_parametrizado }
68
78
  end
69
79
 
70
- passos_gerados << {
71
- conector: conector,
72
- raw: corpo,
73
- param: corpo_parametrizado,
74
- args: param_list,
75
- tipo: tipo
76
- } unless passos_gerados.any? { |p| p[:param] == corpo_parametrizado }
77
80
  end
78
81
 
79
- end
80
-
81
- if passos_gerados.empty?
82
- puts "⚠️ Nenhum passo detectado em: #{nome_arquivo_feature} (arquivo não gerado)"
83
- return false
84
- end
82
+ if passos_gerados.empty?
83
+ puts "⚠️ Nenhum passo detectado em: #{nome_arquivo_feature} (arquivo não gerado)"
84
+ return false
85
+ end
85
86
 
86
- nome_base = File.basename(nome_arquivo_feature, '.feature')
87
- caminho = "steps/#{nome_base}_steps.rb"
88
- FileUtils.mkdir_p(File.dirname(caminho))
87
+ nome_base = File.basename(nome_arquivo_feature, '.feature')
88
+ caminho = "steps/#{nome_base}_steps.rb"
89
+ FileUtils.mkdir_p(File.dirname(caminho))
89
90
 
90
- comentario = "# Step definitions para #{File.basename(nome_arquivo_feature)}"
91
- comentario += idioma == 'en' ? " (English)" : " (Português)"
92
- conteudo = "#{comentario}\n\n"
91
+ comentario = "# Step definitions para #{File.basename(nome_arquivo_feature)}"
92
+ comentario += idioma == 'en' ? " (English)" : " (Português)"
93
+ conteudo = "#{comentario}\n\n"
93
94
 
94
- passos_gerados.each do |passo|
95
- conteudo += <<~STEP
96
- #{passo[:conector]}('#{passo[:param]}') do#{passo[:args].empty? ? '' : " |#{passo[:args]}|"}
97
- pending '#{idioma == 'en' ? 'Implement step' : 'Implementar passo'}: #{passo[:raw]}'
95
+ passos_gerados.each do |passo|
96
+ conteudo += <<~STEP
97
+ #{passo[:conector]}('#{passo[:param]}') do#{passo[:args].empty? ? '' : " |#{passo[:args]}|"}
98
+ pending '#{idioma == 'en' ? 'Implement step' : 'Implementar passo'}: #{passo[:raw]}'
99
+ end
100
+
101
+ STEP
98
102
  end
99
103
 
100
- STEP
104
+ FileUtils.mkdir_p("steps")
105
+ if Bddgenx::Verificador.gerar_arquivo_se_novo(caminho, conteudo)
106
+ puts "✅ Step definitions gerados: #{caminho}"
107
+ else
108
+ puts "⏭️ Steps mantidos: #{caminho}"
109
+ end
110
+ true
101
111
  end
102
112
 
103
- FileUtils.mkdir_p("steps")
104
- if Bddgenx::Verificador.gerar_arquivo_se_novo(caminho, conteudo)
105
- puts "✅ Step definitions gerados: #{caminho}"
106
- else
107
- puts "⏭️ Steps mantidos: #{caminho}"
108
- end
109
- true
110
- end
111
113
 
112
-
113
- def self.substituir_parametros(texto, exemplos)
114
- texto.gsub(/<([^>]+)>/) do |_match|
115
- nome = $1.strip
116
- tipo = detectar_tipo_param(nome, exemplos)
117
- "{#{tipo}}"
114
+ def self.substituir_parametros(texto, exemplos)
115
+ texto.gsub(/<([^>]+)>/) do |_match|
116
+ nome = $1.strip
117
+ tipo = detectar_tipo_param(nome, exemplos)
118
+ "{#{tipo}}"
119
+ end
118
120
  end
119
- end
120
121
 
121
- def self.detectar_tipo_param(nome_coluna, exemplos)
122
- return 'string' unless exemplos && exemplos[:cabecalho].include?(nome_coluna)
122
+ def self.detectar_tipo_param(nome_coluna, exemplos)
123
+ return 'string' unless exemplos && exemplos[:cabecalho].include?(nome_coluna)
123
124
 
124
- idx = exemplos[:cabecalho].index(nome_coluna)
125
- valores = exemplos[:linhas].map { |linha| linha[idx].to_s.strip }
125
+ idx = exemplos[:cabecalho].index(nome_coluna)
126
+ valores = exemplos[:linhas].map { |linha| linha[idx].to_s.strip }
126
127
 
127
- return 'boolean' if valores.all? { |v| %w[true false].include?(v.downcase) }
128
- return 'int' if valores.all? { |v| v.match?(/^\d+$/) }
129
- return 'float' if valores.all? { |v| v.match?(/^\d+\.\d+$/) }
128
+ return 'boolean' if valores.all? { |v| %w[true false].include?(v.downcase) }
129
+ return 'int' if valores.all? { |v| v.match?(/^\d+$/) }
130
+ return 'float' if valores.all? { |v| v.match?(/^\d+\.\d+$/) }
130
131
 
131
- 'string'
132
- end
132
+ 'string'
133
+ end
133
134
 
134
- def self.dividir_examples(tabela_bruta)
135
- grupos = []
136
- grupo_atual = []
135
+ def self.dividir_examples(tabela_bruta)
136
+ grupos = []
137
+ grupo_atual = []
137
138
 
138
- tabela_bruta.each do |linha|
139
- if linha.strip =~ /^\|\s*[\w\s]+\|/ && grupo_atual.any? && linha.strip == linha.strip.squeeze(" ")
140
- grupos << grupo_atual
141
- grupo_atual = [linha]
142
- else
143
- grupo_atual << linha
139
+ tabela_bruta.each do |linha|
140
+ if linha.strip =~ /^\|\s*[\w\s]+\|/ && grupo_atual.any? && linha.strip == linha.strip.squeeze(" ")
141
+ grupos << grupo_atual
142
+ grupo_atual = [linha]
143
+ else
144
+ grupo_atual << linha
145
+ end
144
146
  end
145
- end
146
147
 
147
- grupos << grupo_atual unless grupo_atual.empty?
148
- grupos
149
- end
148
+ grupos << grupo_atual unless grupo_atual.empty?
149
+ grupos
150
+ end
150
151
 
151
152
 
152
- def self.extrair_exemplos(bloco)
153
- return nil unless bloco&.any?
153
+ def self.extrair_exemplos(bloco)
154
+ return nil unless bloco&.any?
154
155
 
155
- linhas = bloco.map(&:strip)
156
- cabecalho = linhas.first.gsub('|', '').split.map(&:strip)
157
- dados = linhas[1..].map { |linha| linha.gsub('|', '').split.map(&:strip) }
156
+ linhas = bloco.map(&:strip)
157
+ cabecalho = linhas.first.gsub('|', '').split.map(&:strip)
158
+ dados = linhas[1..].map { |linha| linha.gsub('|', '').split.map(&:strip) }
158
159
 
159
- { cabecalho: cabecalho, linhas: dados }
160
+ { cabecalho: cabecalho, linhas: dados }
161
+ end
160
162
  end
161
163
  end
162
164
 
@@ -1,31 +1,33 @@
1
1
  require 'csv'
2
2
  require 'fileutils'
3
3
 
4
- module Tracer
5
- ARQUIVO = 'output/rastreabilidade.csv'
4
+ module Bddgenx
5
+ class Tracer
6
+ ARQUIVO = 'output/rastreabilidade.csv'
6
7
 
7
- def self.adicionar_entrada(historia, caminho_arquivo)
8
- FileUtils.mkdir_p("output")
8
+ def self.adicionar_entrada(historia, caminho_arquivo)
9
+ FileUtils.mkdir_p("output")
9
10
 
10
- CSV.open(ARQUIVO, File.exist?(ARQUIVO) ? 'a' : 'w', col_sep: ';') do |csv|
11
- unless File.exist?(ARQUIVO)
12
- csv << ["Funcionalidade", "Tipo de Teste", "Nome do Cenário", "Arquivo .feature"]
13
- end
11
+ CSV.open(ARQUIVO, File.exist?(ARQUIVO) ? 'a' : 'w', col_sep: ';') do |csv|
12
+ unless File.exist?(ARQUIVO)
13
+ csv << ["Funcionalidade", "Tipo de Teste", "Nome do Cenário", "Arquivo .feature"]
14
+ end
14
15
 
15
- historia[:blocos].each do |tipo, passos|
16
- next if tipo == "CONTEXT" || tipo == "EXAMPLES" || passos.empty?
16
+ historia[:blocos].each do |tipo, passos|
17
+ next if tipo == "CONTEXT" || tipo == "EXAMPLES" || passos.empty?
17
18
 
18
- tipo_istqb = tipo.capitalize.gsub('_', ' ').capitalize
19
- contexto = passos.first&.gsub(/^(Dado que|Quando|Então|E)/, '')&.strip || "Condição"
20
- resultado = passos.last&.gsub(/^(Então|E)/, '')&.strip || "Resultado"
21
- nome_cenario = "#{tipo_istqb} - #{contexto} - #{resultado}"
19
+ tipo_istqb = tipo.capitalize.gsub('_', ' ').capitalize
20
+ contexto = passos.first&.gsub(/^(Dado que|Quando|Então|E)/, '')&.strip || "Condição"
21
+ resultado = passos.last&.gsub(/^(Então|E)/, '')&.strip || "Resultado"
22
+ nome_cenario = "#{tipo_istqb} - #{contexto} - #{resultado}"
22
23
 
23
- csv << [
24
- historia[:quero].sub(/^Quero/, '').strip,
25
- tipo_istqb,
26
- nome_cenario,
27
- caminho_arquivo
28
- ]
24
+ csv << [
25
+ historia[:quero].sub(/^Quero/, '').strip,
26
+ tipo_istqb,
27
+ nome_cenario,
28
+ caminho_arquivo
29
+ ]
30
+ end
29
31
  end
30
32
  end
31
33
  end
@@ -1,32 +1,34 @@
1
- module Validator
2
- TIPOS_CENARIO = %w[
3
- SUCCESS
4
- FAILURE
5
- ERROR
6
- EXCEPTION
7
- VALIDATION
8
- PERMISSION
9
- EDGE_CASE
10
- PERFORMANCE
11
- ]
1
+ module Bddgenx
2
+ class Validator
3
+ TIPOS_CENARIO = %w[
4
+ SUCCESS
5
+ FAILURE
6
+ ERROR
7
+ EXCEPTION
8
+ VALIDATION
9
+ PERMISSION
10
+ EDGE_CASE
11
+ PERFORMANCE
12
+ ]
12
13
 
13
- def self.validar(historia)
14
- valido = true
14
+ def self.validar(historia)
15
+ valido = true
15
16
 
16
- if historia[:como].to_s.strip.empty? ||
17
- historia[:quero].to_s.strip.empty? ||
18
- historia[:para].to_s.strip.empty?
19
- puts "❌ História incompleta: 'Como', 'Quero' ou 'Para' está faltando."
20
- valido = false
21
- end
17
+ if historia[:como].to_s.strip.empty? ||
18
+ historia[:quero].to_s.strip.empty? ||
19
+ historia[:para].to_s.strip.empty?
20
+ puts "❌ História incompleta: 'Como', 'Quero' ou 'Para' está faltando."
21
+ valido = false
22
+ end
22
23
 
23
- cenarios_presentes = historia[:blocos].keys & TIPOS_CENARIO
24
- valido ||= historia[:blocos]["CONTEXT"]&.any? || historia[:regras]&.any?
25
- if cenarios_presentes.empty? && !valido
26
- puts "❌ Nenhum conteúdo válido detectado (cenários, contexto ou regras)."
27
- return false
28
- end
24
+ cenarios_presentes = historia[:blocos].keys & TIPOS_CENARIO
25
+ valido ||= historia[:blocos]["CONTEXT"]&.any? || historia[:regras]&.any?
26
+ if cenarios_presentes.empty? && !valido
27
+ puts "❌ Nenhum conteúdo válido detectado (cenários, contexto ou regras)."
28
+ return false
29
+ end
29
30
 
30
- valido
31
+ valido
32
+ end
31
33
  end
32
34
  end
@@ -1,3 +1,3 @@
1
1
  module Bddgenx
2
- VERSION = "0.1.10"
2
+ VERSION = "0.1.11"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bddgenx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Nascimento