my_obfuscate 0.3.0 → 0.3.7

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.
@@ -0,0 +1,91 @@
1
+ class MyObfuscate
2
+ class Mysql
3
+ INSERT_REGEX = /^\s*INSERT INTO `(.*?)` \((.*?)\) VALUES\s*/i
4
+
5
+ def parse_insert_statement(line)
6
+ if regex_match = INSERT_REGEX.match(line)
7
+ {
8
+ :table_name => regex_match[1].to_sym,
9
+ :column_names => regex_match[2].split(/`\s*,\s*`/).map { |col| col.gsub('`', "").to_sym }
10
+ }
11
+ end
12
+ end
13
+
14
+ def rows_to_be_inserted(line)
15
+ line = line.gsub(INSERT_REGEX, '').gsub(/\s*;\s*$/, '')
16
+ context_aware_mysql_string_split(line)
17
+ end
18
+
19
+ def make_valid_value_string(value)
20
+ if value.nil?
21
+ "NULL"
22
+ elsif value =~ /^0x[0-9a-fA-F]+$/
23
+ value
24
+ else
25
+ "'" + value + "'"
26
+ end
27
+ end
28
+
29
+ def make_insert_statement(table_name, column_names, values_strings)
30
+ "INSERT INTO `#{table_name}` (`#{column_names.join('`, `')}`) VALUES #{values_strings};"
31
+ end
32
+
33
+ private
34
+
35
+ # Be aware, strings must be quoted in single quotes!
36
+ def context_aware_mysql_string_split(string)
37
+ in_sub_insert = false
38
+ in_quoted_string = false
39
+ escaped = false
40
+ current_field = nil
41
+ length = string.length
42
+ fields = []
43
+ output = []
44
+
45
+ string.each_char do |i|
46
+ if escaped
47
+ escaped = false
48
+ current_field ||= ""
49
+ current_field << i
50
+ else
51
+ if i == "\\"
52
+ escaped = true
53
+ current_field ||= ""
54
+ current_field << i
55
+ elsif i == "(" && !in_quoted_string && !in_sub_insert
56
+ in_sub_insert = true
57
+ elsif i == ")" && !in_quoted_string && in_sub_insert
58
+ fields << current_field unless current_field.nil?
59
+ output << fields unless fields.length == 0
60
+ in_sub_insert = false
61
+ fields = []
62
+ current_field = nil
63
+ elsif i == "'" && !in_quoted_string
64
+ fields << current_field unless current_field.nil?
65
+ current_field = ''
66
+ in_quoted_string = true
67
+ elsif i == "'" && in_quoted_string
68
+ fields << current_field unless current_field.nil?
69
+ current_field = nil
70
+ in_quoted_string = false
71
+ elsif i == "," && !in_quoted_string && in_sub_insert
72
+ fields << current_field unless current_field.nil?
73
+ current_field = nil
74
+ elsif i == "L" && !in_quoted_string && in_sub_insert && current_field == "NUL"
75
+ current_field = nil
76
+ fields << current_field
77
+ elsif (i == " " || i == "\t") && !in_quoted_string
78
+ # Don't add whitespace not in a string
79
+ elsif in_sub_insert
80
+ current_field ||= ""
81
+ current_field << i
82
+ end
83
+ end
84
+ end
85
+
86
+ fields << current_field unless current_field.nil?
87
+ output << fields unless fields.length == 0
88
+ output
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,81 @@
1
+ class MyObfuscate
2
+ class SqlServer
3
+ INSERT_REGEX = /^\s*INSERT (?:INTO )?\[dbo\]\.\[(.*?)\] \((.*?)\) VALUES\s*/i
4
+
5
+ def parse_insert_statement(line)
6
+ if regex_match = INSERT_REGEX.match(line)
7
+ {
8
+ :table_name => regex_match[1].to_sym,
9
+ :column_names => regex_match[2].split(/\]\s*,\s*\[/).map { |col| col.gsub(/[\[\]]/, "").to_sym }
10
+ }
11
+ end
12
+ end
13
+
14
+ def rows_to_be_inserted(line)
15
+ line = line.gsub(INSERT_REGEX, '').gsub(/\s*;?\s*$/, '').gsub(/^\(/, '').gsub(/\)$/, '')
16
+ context_aware_sql_server_string_split(line)
17
+ end
18
+
19
+ def make_valid_value_string(value)
20
+ if value.nil?
21
+ "NULL"
22
+ elsif value.match(/^[A-Z]+\(.*?\)$/)
23
+ value
24
+ else
25
+ "N'#{value}'"
26
+ end
27
+ end
28
+
29
+ def make_insert_statement(table_name, column_names, values_strings)
30
+ "INSERT [dbo].[#{table_name}] ([#{column_names.join("], [")}]) VALUES #{values_strings};"
31
+ end
32
+
33
+ private
34
+
35
+ def context_aware_sql_server_string_split(string)
36
+ in_quoted_string = false
37
+ backslash_escape = false
38
+ previous_char_single_quote = false
39
+ current_field_value = nil
40
+ completed_fields = []
41
+
42
+ string.each_char do |char|
43
+ if char == "'" && !in_quoted_string
44
+ if current_field_value != "N"
45
+ completed_fields << current_field_value unless current_field_value.nil?
46
+ end
47
+ current_field_value = ""
48
+ in_quoted_string = true
49
+ elsif previous_char_single_quote
50
+ previous_char_single_quote = false
51
+ if char == "'"
52
+ current_field_value << "''"
53
+ else
54
+ completed_fields << current_field_value unless current_field_value.nil?
55
+ in_quoted_string = false
56
+ current_field_value = nil
57
+ end
58
+ elsif char == "'" && in_quoted_string
59
+ previous_char_single_quote = true
60
+ elsif char == "," && !in_quoted_string
61
+ completed_fields << current_field_value unless current_field_value.nil?
62
+ current_field_value = nil
63
+ elsif char == "L" && !in_quoted_string && current_field_value == "NUL"
64
+ current_field_value = nil
65
+ completed_fields << current_field_value
66
+ elsif (char == " " || char == "\t") && !in_quoted_string
67
+ if !current_field_value.nil? && current_field_value.start_with?("CAST(")
68
+ current_field_value << char
69
+ end
70
+ # Don't add whitespace not in a string
71
+ else
72
+ current_field_value ||= ""
73
+ current_field_value << char
74
+ end
75
+ end
76
+
77
+ completed_fields << current_field_value unless current_field_value.nil?
78
+ [completed_fields]
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ class MyObfuscate
2
+ VERSION = "0.3.7"
3
+ end
data/my_obfuscate.gemspec CHANGED
@@ -1,54 +1,22 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
1
  # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "my_obfuscate/version"
5
4
 
6
5
  Gem::Specification.new do |s|
7
6
  s.name = %q{my_obfuscate}
8
- s.version = "0.3.0"
7
+ s.version = MyObfuscate::VERSION
9
8
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Andrew Cantino", "Dave Willett", "Mike Grafton", "Mason Glaves"]
12
- s.date = %q{2009-10-09}
9
+ s.authors = ["Andrew Cantino", "Dave Willett", "Mike Grafton", "Mason Glaves", "Greg Bell", "Mavenlink"]
13
10
  s.description = %q{Standalone Ruby code for the selective rewriting of MySQL dumps in order to protect user privacy.}
14
- s.email = %q{andrew@pivotallabs.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "lib/my_obfuscate.rb",
27
- "my_obfuscate.gemspec",
28
- "spec/my_obfuscate_spec.rb",
29
- "spec/spec_helper.rb"
30
- ]
31
- s.homepage = %q{http://github.com/honkster/myobfuscate}
32
- s.rdoc_options = ["--charset=UTF-8"]
33
- s.require_paths = ["lib"]
34
- s.rubyforge_project = %q{my-obfuscate}
35
- s.rubygems_version = %q{1.3.5}
11
+ s.email = %q{andrew@iterationlabs.com}
12
+ s.homepage = %q{http://github.com/iterationlabs/my_obfuscate}
36
13
  s.summary = %q{Standalone Ruby code for the selective rewriting of MySQL dumps in order to protect user privacy.}
37
- s.test_files = [
38
- "spec/my_obfuscate_spec.rb",
39
- "spec/spec_helper.rb"
40
- ]
41
14
 
42
- if s.respond_to? :specification_version then
43
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
- s.specification_version = 3
15
+ s.add_development_dependency "rspec"
16
+ s.add_dependency "faker", ">= 1.0.1"
45
17
 
46
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
- s.add_development_dependency(%q<rspec>, [">= 0"])
48
- else
49
- s.add_dependency(%q<rspec>, [">= 0"])
50
- end
51
- else
52
- s.add_dependency(%q<rspec>, [">= 0"])
53
- end
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
54
22
  end
@@ -1,51 +1,19 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe MyObfuscate do
4
- describe "MyObfuscate.context_aware_mysql_string_split" do
5
- it "should split a mysql string into fields" do
6
- string = "('bob@bob.com','bob', 'somethingelse1', 25, '2', 10, 'hi')"
7
- fields = [['bob@bob.com', 'bob', 'somethingelse1', '25', '2', '10', "hi"]]
8
- MyObfuscate.context_aware_mysql_string_split(string).should == fields
9
- end
10
-
11
- it "should work ok with escaped characters" do
12
- string = "('bob,@bob.c , om', 'bo\\', b', 'some\"thin\\gel\\\\\\'se1', 25, '2', 10, 'hi', 5)"
13
- fields = [['bob,@bob.c , om', 'bo\\\', b', 'some"thin\\gel\\\\\\\'se1', '25', '2', '10', "hi", "5"]]
14
- MyObfuscate.context_aware_mysql_string_split(string).should == fields
15
- end
16
-
17
- it "should work with multiple subinserts" do
18
- string = "(1,2,3, '((m))(oo()s,e'), ('bob,@bob.c , om', 'bo\\', b', 'some\"thin\\gel\\\\\\'se1', 25, '2', 10, 'hi', 5)"
19
- fields = [["1", "2", "3", "((m))(oo()s,e"], ['bob,@bob.c , om', 'bo\\\', b', 'some"thin\\gel\\\\\\\'se1', '25', '2', '10', "hi", "5"]]
20
- MyObfuscate.context_aware_mysql_string_split(string).should == fields
21
- end
22
-
23
- it "should work ok with NULL values" do
24
- string = "(NULL , 'bob@bob.com','bob', NULL, 25, '2', NULL, 'hi', NULL )"
25
- fields = [[nil, 'bob@bob.com', 'bob', nil, '25', '2', nil, "hi", nil]]
26
- MyObfuscate.context_aware_mysql_string_split(string).should == fields
27
- end
28
-
29
- it "should work with empty strings" do
30
- string = "(NULL , '', '' , '', 25, '2','', 'hi','')"
31
- fields = [[nil, '', '', '', '25', '2', '', "hi", '']]
32
- MyObfuscate.context_aware_mysql_string_split(string).should == fields
33
- end
34
- end
35
-
36
- describe "MyObfuscate.reasembling_each_insert" do
4
+ describe "MyObfuscate.reassembling_each_insert" do
37
5
  before do
38
6
  @column_names = [:a, :b, :c, :d]
39
7
  @test_insert = "INSERT INTO `some_table` (`a`, `b`, `c`, `d`) VALUES ('(\\'bob@bob.com','b()ob','some(thingelse1','25)('),('joe@joe.com','joe','somethingelse2','54');"
40
8
  @test_insert_passes = [
41
- ["(\\'bob@bob.com","b()ob", "some(thingelse1", "25)("],
42
- ["joe@joe.com","joe", "somethingelse2", "54"]
9
+ ["(\\'bob@bob.com", "b()ob", "some(thingelse1", "25)("],
10
+ ["joe@joe.com", "joe", "somethingelse2", "54"]
43
11
  ]
44
12
  end
45
13
 
46
14
  it "should yield each subinsert and reassemble the result" do
47
15
  count = 0
48
- reassembled = MyObfuscate.reasembling_each_insert(@test_insert, "some_table", @column_names) do |sub_insert|
16
+ reassembled = MyObfuscate.new.reassembling_each_insert(@test_insert, "some_table", @column_names) do |sub_insert|
49
17
  sub_insert.should == @test_insert_passes.shift
50
18
  count += 1
51
19
  sub_insert
@@ -57,13 +25,13 @@ describe MyObfuscate do
57
25
 
58
26
  describe "MyObfuscate.apply_table_config" do
59
27
  it "should work on email addresses" do
60
- new_row = MyObfuscate.apply_table_config(["blah", "something_else"], { :a => { :type => :email }}, [:a, :b])
28
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else"], {:a => {:type => :email}}, [:a, :b])
61
29
  new_row.length.should == 2
62
- new_row.first.should =~ /^\w+\@\w+\.\w+$/
30
+ new_row.first.should =~ /^[\w\.]+\@\w+\.\w+$/
63
31
  end
64
32
 
65
33
  it "should work on strings" do
66
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "something crazy"], { :b => { :type => :string, :length => 7 }}, [:a, :b, :c])
34
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "something crazy"], {:b => {:type => :string, :length => 7}}, [:a, :b, :c])
67
35
  new_row.length.should == 3
68
36
  new_row[1].length.should == 7
69
37
  new_row[1].should_not == "something_else"
@@ -71,67 +39,95 @@ describe MyObfuscate do
71
39
 
72
40
  describe "conditional directives" do
73
41
  it "should honor :unless conditionals" do
74
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :unless => lambda {|row| row[:a] == "blah"} }}, [:a, :b, :c])
42
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :unless => lambda { |row| row[:a] == "blah" }}}, [:a, :b, :c])
75
43
  new_row[0].should_not == "123"
76
44
  new_row[0].should == "blah"
77
45
 
78
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :unless => lambda {|row| row[:a] == "not blah"} }}, [:a, :b, :c])
46
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :unless => lambda { |row| row[:a] == "not blah" }}}, [:a, :b, :c])
79
47
  new_row[0].should == "123"
48
+
49
+ new_row = MyObfuscate.apply_table_config([nil, "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :unless => :nil}, :b=> {:type => :fixed, :string => "123", :unless => :nil}}, [:a, :b, :c])
50
+ new_row[0].should == nil
51
+ new_row[1].should == "123"
52
+
53
+ new_row = MyObfuscate.apply_table_config(['', "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :unless => :blank}, :b=> {:type => :fixed, :string => "123", :unless => :blank}}, [:a, :b, :c])
54
+ new_row[0].should == ''
55
+ new_row[1].should == "123"
80
56
  end
81
57
 
82
58
  it "should honor :if conditionals" do
83
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if => lambda {|row| row[:a] == "blah"} }}, [:a, :b, :c])
59
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => lambda { |row| row[:a] == "blah" }}}, [:a, :b, :c])
84
60
  new_row[0].should == "123"
85
61
 
86
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if=> lambda {|row| row[:a] == "not blah"} }}, [:a, :b, :c])
62
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if=> lambda { |row| row[:a] == "not blah" }}}, [:a, :b, :c])
87
63
  new_row[0].should_not == "123"
88
64
  new_row[0].should == "blah"
65
+
66
+ new_row = MyObfuscate.apply_table_config([nil, "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => :nil}, :b=> {:type => :fixed, :string => "123", :if => :nil}}, [:a, :b, :c])
67
+ new_row[0].should == "123"
68
+ new_row[1].should == "something_else"
69
+
70
+ new_row = MyObfuscate.apply_table_config(['', "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => :blank}, :b=> {:type => :fixed, :string => "123", :if => :blank}}, [:a, :b, :c])
71
+ new_row[0].should == "123"
72
+ new_row[1].should == "something_else"
89
73
  end
90
74
 
91
75
  it "should supply the original row values to the conditional" do
92
- new_row = MyObfuscate.apply_table_config(["blah", "something_else"], { :a => { :type => :fixed, :string => "123" }, :b => { :type => :fixed, :string => "yup", :if => lambda {|row| row[:a] == "blah"}}}, [:a, :b])
76
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else"], {:a => {:type => :fixed, :string => "123"}, :b => {:type => :fixed, :string => "yup", :if => lambda { |row| row[:a] == "blah" }}}, [:a, :b])
93
77
  new_row[0].should == "123"
94
78
  new_row[1].should == "yup"
95
79
  end
96
80
 
97
81
  it "should honor combined :unless and :if conditionals" do
98
82
  #both true
99
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if => lambda {|row| row[:a] == "blah"}, :unless => lambda {|row| row[:b] == "something_else"} }}, [:a, :b, :c])
83
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => lambda { |row| row[:a] == "blah" }, :unless => lambda { |row| row[:b] == "something_else" }}}, [:a, :b, :c])
100
84
  new_row[0].should == "blah"
101
85
 
102
86
  #both false
103
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if => lambda {|row| row[:a] == "not blah"}, :unless => lambda {|row| row[:b] == "not something_else"} }}, [:a, :b, :c])
87
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => lambda { |row| row[:a] == "not blah" }, :unless => lambda { |row| row[:b] == "not something_else" }}}, [:a, :b, :c])
104
88
  new_row[0].should == "blah"
105
89
 
106
90
  #if true, #unless false
107
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if => lambda {|row| row[:a] == "blah"}, :unless => lambda {|row| row[:b] == "not something_else"} }}, [:a, :b, :c])
91
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => lambda { |row| row[:a] == "blah" }, :unless => lambda { |row| row[:b] == "not something_else" }}}, [:a, :b, :c])
108
92
  new_row[0].should == "123"
109
93
 
110
94
  #if false, #unless true
111
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a=> { :type => :fixed, :string => "123", :if => lambda {|row| row[:a] == "not blah"}, :unless => lambda {|row| row[:b] == "something_else"} }}, [:a, :b, :c])
95
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a=> {:type => :fixed, :string => "123", :if => lambda { |row| row[:a] == "not blah" }, :unless => lambda { |row| row[:b] == "something_else" }}}, [:a, :b, :c])
112
96
  new_row[0].should == "blah"
113
97
  end
114
98
  end
115
99
 
116
100
  it "should be able to generate random integers in ranges" do
117
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :c => { :type => :integer, :between => 10..100 }}, [:a, :b, :c])
101
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:c => {:type => :integer, :between => 10..100}}, [:a, :b, :c])
118
102
  new_row.length.should == 3
119
103
  new_row[2].to_i.to_s.should == new_row[2] # It should be an integer.
120
104
  new_row[2].should_not == "5"
121
105
  end
122
106
 
123
107
  it "should be able to substitute fixed strings" do
124
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :b => { :type => :fixed, :string => "hello" }}, [:a, :b, :c])
108
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :fixed, :string => "hello"}}, [:a, :b, :c])
125
109
  new_row.length.should == 3
126
110
  new_row[1].should == "hello"
127
111
  end
128
112
 
113
+ it "should be able to substitute a proc that returns a string" do
114
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :fixed, :string => proc { "Hello World" }}}, [:a, :b, :c])
115
+ new_row.length.should == 3
116
+ new_row[1].should == "Hello World"
117
+ end
118
+
119
+ it "should provide the row to the proc" do
120
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :fixed, :string => proc { |a| a[:b] }}}, [:a, :b, :c])
121
+ new_row.length.should == 3
122
+ new_row[1].should == "something_else"
123
+ end
124
+
129
125
  it "should be able to substitute fixed strings from a random set" do
130
126
  looking_for = ["hello", "world"]
131
127
  original_looking_for = looking_for.dup
132
128
  guard = 0
133
129
  while !looking_for.empty? && guard < 1000
134
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :a => { :type => :fixed, :one_of => ["hello", "world"] }}, [:a, :b, :c])
130
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => {:type => :fixed, :one_of => ["hello", "world"]}}, [:a, :b, :c])
135
131
  new_row.length.should == 3
136
132
  original_looking_for.should include(new_row[0])
137
133
  looking_for.delete new_row[0]
@@ -140,12 +136,135 @@ describe MyObfuscate do
140
136
  looking_for.should be_empty
141
137
  end
142
138
 
139
+ it "should treat a symbol in the column definition as an implicit { :type => symbol }" do
140
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => :null, :a => :keep}, [:a, :b, :c])
141
+ new_row.length.should == 3
142
+ new_row[0].should == "blah"
143
+ new_row[1].should == nil
144
+ end
145
+
143
146
  it "should be able to set things NULL" do
144
- new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], { :b => { :type => :null }}, [:a, :b, :c])
147
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :null}}, [:a, :b, :c])
145
148
  new_row.length.should == 3
146
149
  new_row[1].should == nil
147
150
  end
148
151
 
152
+ it "should be able to :keep the value the same" do
153
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :keep}}, [:a, :b, :c])
154
+ new_row.length.should == 3
155
+ new_row[1].should == "something_else"
156
+ end
157
+
158
+ it "should keep the value when given an unknown type, but should display a warning" do
159
+ $stderr = error_output = StringIO.new
160
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:b => {:type => :unknown_type}}, [:a, :b, :c])
161
+ $stderr = STDERR
162
+ new_row.length.should == 3
163
+ new_row[1].should == "something_else"
164
+ error_output.rewind
165
+ error_output.read.should =~ /Keeping a column value by.*?unknown_type/
166
+ end
167
+
168
+ it "should be able to substitute lorem ipsum text" do
169
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :lorem, :b => {:type => :lorem, :number => 2}}, [:a, :b, :c])
170
+ new_row.length.should == 3
171
+ new_row[0].should_not == "blah"
172
+ new_row[0].should_not =~ /\w\.(?!\Z)/
173
+ new_row[1].should_not == "something_else"
174
+ new_row[1].should =~ /\w\.(?!\Z)/
175
+ end
176
+
177
+ it "should be able to generate an :company" do
178
+ new_row = MyObfuscate.apply_table_config(["Smith and Sons", "something_else", "5"], {:a => :company}, [:a, :b, :c])
179
+ new_row.length.should == 3
180
+ new_row[0].should_not == "Smith and Sons"
181
+ new_row[0].should =~ /\w+/
182
+ end
183
+
184
+ it "should be able to generate an :url" do
185
+ new_row = MyObfuscate.apply_table_config(["http://mystuff.blogger.com", "something_else", "5"], {:a => :url}, [:a, :b, :c])
186
+ new_row.length.should == 3
187
+ new_row[0].should_not == "http://mystuff.blogger.com"
188
+ new_row[0].should =~ /http:\/\/\w+/
189
+ end
190
+
191
+ it "should be able to generate an :ipv4" do
192
+ new_row = MyObfuscate.apply_table_config(["1.2.3.4", "something_else", "5"], {:a => :ipv4}, [:a, :b, :c])
193
+ new_row.length.should == 3
194
+ new_row[0].should_not == "1.2.3.4"
195
+ new_row[0].should =~ /\d+\.\d+\.\d+\.\d+/
196
+ end
197
+
198
+ it "should be able to generate an :ipv6" do
199
+ new_row = MyObfuscate.apply_table_config(["fe80:0000:0000:0000:0202:b3ff:fe1e:8329", "something_else", "5"], {:a => :ipv6}, [:a, :b, :c])
200
+ new_row.length.should == 3
201
+ new_row[0].should_not == "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
202
+ new_row[0].should =~ /[0-9a-f:]+/
203
+ end
204
+
205
+ it "should be able to generate an :address" do
206
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :address}, [:a, :b, :c])
207
+ new_row.length.should == 3
208
+ new_row[0].should_not == "blah"
209
+ new_row[0].should =~ /\d+ \w/
210
+ end
211
+
212
+ it "should be able to generate a :name" do
213
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :name}, [:a, :b, :c])
214
+ new_row.length.should == 3
215
+ new_row[0].should_not == "blah"
216
+ new_row[0].should =~ / /
217
+ end
218
+
219
+ it "should be able to generate just a street address" do
220
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :street_address}, [:a, :b, :c])
221
+ new_row.length.should == 3
222
+ new_row[0].should_not == "blah"
223
+ new_row[0].should =~ /\d+ \w/
224
+ end
225
+
226
+ it "should be able to generate a city" do
227
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :city}, [:a, :b, :c])
228
+ new_row.length.should == 3
229
+ new_row[0].should_not == "blah"
230
+ end
231
+
232
+ it "should be able to generate a state" do
233
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :state}, [:a, :b, :c])
234
+ new_row.length.should == 3
235
+ new_row[0].should_not == "blah"
236
+ end
237
+
238
+ it "should be able to generate a zip code" do
239
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :zip_code}, [:a, :b, :c])
240
+ new_row.length.should == 3
241
+ new_row[0].should_not == "blah"
242
+ new_row[0].should =~ /\d+/
243
+ end
244
+
245
+ it "should be able to generate a phone number" do
246
+ new_row = MyObfuscate.apply_table_config(["blah", "something_else", "5"], {:a => :phone}, [:a, :b, :c])
247
+ new_row.length.should == 3
248
+ new_row[0].should_not == "blah"
249
+ new_row[0].should =~ /\d+/
250
+ end
251
+
252
+ describe "when faker generates values with quotes in them" do
253
+ before do
254
+ Faker::Address.stub(:city).and_return("O'ReillyTown")
255
+ Faker::Name.stub(:name).and_return("Foo O'Reilly")
256
+ Faker::Name.stub(:first_name).and_return("O'Foo")
257
+ Faker::Name.stub(:last_name).and_return("O'Reilly")
258
+ Faker::Lorem.stub(:sentences).with(any_args).and_return(["Foo bar O'Thingy"])
259
+ end
260
+
261
+ it "should remove single quotes from the value" do
262
+ new_row = MyObfuscate.apply_table_config(["address", "city", "first", "last", "fullname", "some text"],
263
+ {:a => :address, :b => :city, :c => :first_name, :d => :last_name, :e => :name, :f => :lorem},
264
+ [:a, :b, :c, :d, :e, :f])
265
+ new_row.each {|value| value.should_not include("'")}
266
+ end
267
+ end
149
268
  end
150
269
 
151
270
  describe "MyObfuscate.row_as_hash" do
@@ -155,91 +274,285 @@ describe MyObfuscate do
155
274
  end
156
275
 
157
276
  describe "#obfuscate" do
158
- context "when there is nothing to obfuscate" do
159
- it "should accept an IO object for input and output, and copy the input to the output" do
160
- ddo = MyObfuscate.new
161
- string = "hello, world\nsup?"
162
- input = StringIO.new(string)
163
- output = StringIO.new
164
- ddo.obfuscate(input, output)
165
- input.rewind
166
- output.rewind
167
- output.read.should == string
277
+ describe "when using MySQL" do
278
+ context "when there is nothing to obfuscate" do
279
+ it "should accept an IO object for input and output, and copy the input to the output" do
280
+ ddo = MyObfuscate.new
281
+ string = "hello, world\nsup?"
282
+ input = StringIO.new(string)
283
+ output = StringIO.new
284
+ ddo.obfuscate(input, output)
285
+ input.rewind
286
+ output.rewind
287
+ output.read.should == string
288
+ end
168
289
  end
169
- end
170
290
 
171
- context "when the dump to obfuscate is missing columns" do
172
- before do
173
- @database_dump = StringIO.new(<<-SQL)
291
+ context "when the dump to obfuscate is missing columns" do
292
+ before do
293
+ @database_dump = StringIO.new(<<-SQL)
174
294
  INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES ('bob@honk.com','bob', 'some\\'thin,ge())lse1', 25),('joe@joe.com','joe', 'somethingelse2', 54);
175
- SQL
176
- @ddo = MyObfuscate.new({
177
- :some_table => {
178
- :email => { :type => :email, :honk_email_skip => true },
179
- :name => { :type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS },
180
- :gender => { :type => :fixed, :string => "m" }
181
- }})
182
- @output = StringIO.new
183
- end
184
-
185
- it "should raise an error if a column name can't be found" do
186
- lambda {
187
- @ddo.obfuscate(@database_dump, @output)
188
- }.should raise_error
295
+ SQL
296
+ @ddo = MyObfuscate.new({
297
+ :some_table => {
298
+ :email => {:type => :email, :honk_email_skip => true},
299
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
300
+ :gender => {:type => :fixed, :string => "m"}
301
+ }})
302
+ @output = StringIO.new
303
+ end
304
+
305
+ it "should raise an error if a column name can't be found" do
306
+ lambda {
307
+ @ddo.obfuscate(@database_dump, @output)
308
+ }.should raise_error
309
+ end
189
310
  end
190
- end
191
311
 
192
- context "when there is something to obfuscate" do
193
- before do
194
- @database_dump = StringIO.new(<<-SQL)
312
+ context "when there is something to obfuscate" do
313
+ before do
314
+ @database_dump = StringIO.new(<<-SQL)
195
315
  INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES ('bob@honk.com','bob', 'some\\'thin,ge())lse1', 25),('joe@joe.com','joe', 'somethingelse2', 54),('dontmurderme@direwolf.com','direwolf', 'somethingelse3', 44);
196
316
  INSERT INTO `another_table` (`a`, `b`, `c`, `d`) VALUES (1,2,3,4), (5,6,7,8);
317
+ INSERT INTO `some_table_to_keep` (`a`, `b`, `c`, `d`) VALUES (1,2,3,4), (5,6,7,8);
197
318
  INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','kjhjd^&dkjh', 'aawefjkafe'), ('hello1','kjhj!', 892938), ('hello2','moose!!', NULL);
198
319
  INSERT INTO `an_ignored_table` (`col`, `col2`) VALUES ('hello','kjhjd^&dkjh'), ('hello1','kjhj!'), ('hello2','moose!!');
199
- SQL
200
-
201
- @ddo = MyObfuscate.new({
202
- :some_table => {
203
- :email => { :type => :email, :skip_regexes => [/^[\w\.\_]+@honk\.com$/i, /^dontmurderme@direwolf.com$/] },
204
- :name => { :type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS },
205
- :age => { :type => :integer, :between => 10...80 }
206
- },
207
- :another_table => :truncate,
208
- :one_more_table => {
209
- # Note: fixed strings must be pre-SQL escaped!
210
- :password => { :type => :fixed, :string => "monkey" },
211
- :c => { :type => :null }
212
- }
213
- })
214
- @output = StringIO.new
215
- @ddo.obfuscate(@database_dump, @output)
216
- @output.rewind
217
- @output_string = @output.read
218
- end
219
-
220
- it "should be able to truncate tables" do
221
- @output_string.should_not include("INSERT INTO `another_table`")
222
- @output_string.should include("INSERT INTO `one_more_table`")
223
- end
224
-
225
- it "should ignore tables that it doesn't know about" do
226
- @output_string.should include("INSERT INTO `an_ignored_table` (`col`, `col2`) VALUES ('hello','kjhjd^&dkjh'), ('hello1','kjhj!'), ('hello2','moose!!');")
227
- end
228
-
229
- it "should obfuscate the tables" do
230
- @output_string.should include("INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES (")
231
- @output_string.should include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES (")
232
- @output_string.should include("'some\\'thin,ge())lse1'")
233
- @output_string.should include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','monkey',NULL),('hello1','monkey',NULL),('hello2','monkey',NULL);")
234
- @output_string.should_not include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','kjhjd^&dkjh', 'aawefjkafe'), ('hello1','kjhj!', 892938), ('hello2','moose!!', NULL);")
235
- @output_string.should_not include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','kjhjd^&dkjh','aawefjkafe'),('hello1','kjhj!',892938),('hello2','moose!!',NULL);")
236
- @output_string.should_not include("INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES ('bob@honk.com','bob', 'some\\'thin,ge())lse1', 25),('joe@joe.com','joe', 'somethingelse2', 54);")
237
- end
238
-
239
- it "honors a special case: on the people table, rows with anything@honk.com in a slot marked with :honk_email_skip do not change this slot" do
240
- @output_string.should include("('bob@honk.com',")
241
- @output_string.should include("('dontmurderme@direwolf.com',")
242
- @output_string.should_not include("joe@joe.com")
320
+ SQL
321
+
322
+ @ddo = MyObfuscate.new({
323
+ :some_table => {
324
+ :email => {:type => :email, :skip_regexes => [/^[\w\.\_]+@honk\.com$/i, /^dontmurderme@direwolf.com$/]},
325
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
326
+ :age => {:type => :integer, :between => 10...80}
327
+ },
328
+ :another_table => :truncate,
329
+ :some_table_to_keep => :keep,
330
+ :one_more_table => {
331
+ # Note: fixed strings must be pre-SQL escaped!
332
+ :password => {:type => :fixed, :string => "monkey"},
333
+ :c => {:type => :null}
334
+ }
335
+ })
336
+ @output = StringIO.new
337
+ $stderr = @error_output = StringIO.new
338
+ @ddo.obfuscate(@database_dump, @output)
339
+ $stderr = STDERR
340
+ @output.rewind
341
+ @output_string = @output.read
342
+ end
343
+
344
+ it "should be able to truncate tables" do
345
+ @output_string.should_not include("INSERT INTO `another_table`")
346
+ @output_string.should include("INSERT INTO `one_more_table`")
347
+ end
348
+
349
+ it "should be able to declare tables to keep" do
350
+ @output_string.should include("INSERT INTO `some_table_to_keep` (`a`, `b`, `c`, `d`) VALUES (1,2,3,4), (5,6,7,8);")
351
+ end
352
+
353
+ it "should ignore tables that it doesn't know about, but should warn" do
354
+ @output_string.should include("INSERT INTO `an_ignored_table` (`col`, `col2`) VALUES ('hello','kjhjd^&dkjh'), ('hello1','kjhj!'), ('hello2','moose!!');")
355
+ @error_output.rewind
356
+ @error_output.read.should =~ /an_ignored_table was not specified in the config/
357
+ end
358
+
359
+ it "should obfuscate the tables" do
360
+ @output_string.should include("INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES (")
361
+ @output_string.should include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES (")
362
+ @output_string.should include("'some\\'thin,ge())lse1'")
363
+ @output_string.should include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','monkey',NULL),('hello1','monkey',NULL),('hello2','monkey',NULL);")
364
+ @output_string.should_not include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','kjhjd^&dkjh', 'aawefjkafe'), ('hello1','kjhj!', 892938), ('hello2','moose!!', NULL);")
365
+ @output_string.should_not include("INSERT INTO `one_more_table` (`a`, `password`, `c`, `d,d`) VALUES ('hello','kjhjd^&dkjh','aawefjkafe'),('hello1','kjhj!',892938),('hello2','moose!!',NULL);")
366
+ @output_string.should_not include("INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES ('bob@honk.com','bob', 'some\\'thin,ge())lse1', 25),('joe@joe.com','joe', 'somethingelse2', 54);")
367
+ end
368
+
369
+ it "honors a special case: on the people table, rows with anything@honk.com in a slot marked with :honk_email_skip do not change this slot" do
370
+ @output_string.should include("('bob@honk.com',")
371
+ @output_string.should include("('dontmurderme@direwolf.com',")
372
+ @output_string.should_not include("joe@joe.com")
373
+ end
374
+ end
375
+
376
+ context "when fail_on_unspecified_columns is set to true" do
377
+ before do
378
+ @database_dump = StringIO.new(<<-SQL)
379
+ INSERT INTO `some_table` (`email`, `name`, `something`, `age`) VALUES ('bob@honk.com','bob', 'some\\'thin,ge())lse1', 25),('joe@joe.com','joe', 'somethingelse2', 54),('dontmurderme@direwolf.com','direwolf', 'somethingelse3', 44);
380
+ SQL
381
+
382
+ @ddo = MyObfuscate.new({
383
+ :some_table => {
384
+ :email => {:type => :email, :skip_regexes => [/^[\w\.\_]+@honk\.com$/i, /^dontmurderme@direwolf.com$/]},
385
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
386
+ :age => {:type => :integer, :between => 10...80}
387
+ }
388
+ })
389
+ @ddo.fail_on_unspecified_columns = true
390
+ end
391
+
392
+ it "should raise an exception when an unspecified column is found" do
393
+ lambda {
394
+ @ddo.obfuscate(@database_dump, StringIO.new)
395
+ }.should raise_error(/column 'something' defined/i)
396
+ end
397
+
398
+ it "should accept columns defined in globally_kept_columns" do
399
+ @ddo.globally_kept_columns = %w[something]
400
+ lambda {
401
+ @ddo.obfuscate(@database_dump, StringIO.new)
402
+ }.should_not raise_error
403
+ end
404
+ end
405
+ end
406
+
407
+ describe "when using MS SQL Server" do
408
+ context "when there is nothing to obfuscate" do
409
+ it "should accept an IO object for input and output, and copy the input to the output" do
410
+ ddo = MyObfuscate.new
411
+ ddo.database_type = :sql_server
412
+ string = "hello, world\nsup?"
413
+ input = StringIO.new(string)
414
+ output = StringIO.new
415
+ ddo.obfuscate(input, output)
416
+ input.rewind
417
+ output.rewind
418
+ output.read.should == string
419
+ end
420
+ end
421
+
422
+ context "when the dump to obfuscate is missing columns" do
423
+ before do
424
+ @database_dump = StringIO.new(<<-SQL)
425
+ INSERT [dbo].[some_table] ([email], [name], [something], [age]) VALUES ('bob@honk.com','bob', 'some''thin,ge())lse1', 25);
426
+ SQL
427
+ @ddo = MyObfuscate.new({
428
+ :some_table => {
429
+ :email => {:type => :email, :honk_email_skip => true},
430
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
431
+ :gender => {:type => :fixed, :string => "m"}
432
+ }})
433
+ @ddo.database_type = :sql_server
434
+ @output = StringIO.new
435
+ end
436
+
437
+ it "should raise an error if a column name can't be found" do
438
+ lambda {
439
+ @ddo.obfuscate(@database_dump, @output)
440
+ }.should raise_error
441
+ end
442
+ end
443
+
444
+ context "when there is something to obfuscate" do
445
+ before do
446
+ @database_dump = StringIO.new(<<-SQL)
447
+ INSERT [dbo].[some_table] ([email], [name], [something], [age], [bday]) VALUES (N'bob@honk.com',N'bob', N'some''thin,ge())lse1', 25, CAST(0x00009E1A00000000 AS DATETIME));
448
+ INSERT [dbo].[some_table] ([email], [name], [something], [age], [bday]) VALUES (N'joe@joe.com',N'joe', N'somethingelse2', 54, CAST(0x00009E1A00000000 AS DATETIME));
449
+ INSERT [dbo].[some_table] ([email], [name], [something], [age], [bday]) VALUES (N'dontmurderme@direwolf.com',N'direwolf', N'somethingelse3', 44, CAST(0x00009E1A00000000 AS DATETIME));
450
+ INSERT [dbo].[another_table] ([a], [b], [c], [d]) VALUES (1,2,3,4);
451
+ INSERT [dbo].[another_table] ([a], [b], [c], [d]) VALUES (5,6,7,8);
452
+ INSERT [dbo].[some_table_to_keep] ([a], [b], [c], [d]) VALUES (1,2,3,4);
453
+ INSERT [dbo].[some_table_to_keep] ([a], [b], [c], [d]) VALUES (5,6,7,8);
454
+ INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello',N'kjhjd^&dkjh', N'aawefjkafe');
455
+ INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello1',N'kjhj!', 892938);
456
+ INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello2',N'moose!!', NULL);
457
+ INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello',N'kjhjd^&dkjh');
458
+ INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello1',N'kjhj!');
459
+ INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello2',N'moose!!');
460
+ SQL
461
+
462
+ @ddo = MyObfuscate.new({
463
+ :some_table => {
464
+ :email => {:type => :email, :skip_regexes => [/^[\w\.\_]+@honk\.com$/i, /^dontmurderme@direwolf.com$/]},
465
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
466
+ :age => {:type => :integer, :between => 10...80},
467
+ :bday => :keep
468
+ },
469
+ :another_table => :truncate,
470
+ :some_table_to_keep => :keep,
471
+ :one_more_table => {
472
+ # Note: fixed strings must be pre-SQL escaped!
473
+ :password => {:type => :fixed, :string => "monkey"},
474
+ :c => {:type => :null}
475
+ }
476
+ })
477
+ @ddo.database_type = :sql_server
478
+
479
+ @output = StringIO.new
480
+ $stderr = @error_output = StringIO.new
481
+ @ddo.obfuscate(@database_dump, @output)
482
+ $stderr = STDERR
483
+ @output.rewind
484
+ @output_string = @output.read
485
+ end
486
+
487
+ it "should be able to truncate tables" do
488
+ @output_string.should_not include("INSERT [dbo].[another_table]")
489
+ @output_string.should include("INSERT [dbo].[one_more_table]")
490
+ end
491
+
492
+ it "should be able to declare tables to keep" do
493
+ @output_string.should include("INSERT [dbo].[some_table_to_keep] ([a], [b], [c], [d]) VALUES (1,2,3,4);")
494
+ @output_string.should include("INSERT [dbo].[some_table_to_keep] ([a], [b], [c], [d]) VALUES (5,6,7,8);")
495
+ end
496
+
497
+ it "should ignore tables that it doesn't know about, but should warn" do
498
+ @output_string.should include("INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello',N'kjhjd^&dkjh');")
499
+ @output_string.should include("INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello1',N'kjhj!');")
500
+ @output_string.should include("INSERT [dbo].[an_ignored_table] ([col], [col2]) VALUES (N'hello2',N'moose!!');")
501
+ @error_output.rewind
502
+ @error_output.read.should =~ /an_ignored_table was not specified in the config/
503
+ end
504
+
505
+ it "should obfuscate the tables" do
506
+ @output_string.should include("INSERT [dbo].[some_table] ([email], [name], [something], [age], [bday]) VALUES (")
507
+ @output_string.should include("CAST(0x00009E1A00000000 AS DATETIME)")
508
+ @output_string.should include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (")
509
+ @output_string.should include("'some''thin,ge())lse1'")
510
+ @output_string.should include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello',N'monkey',NULL);")
511
+ @output_string.should include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello1',N'monkey',NULL);")
512
+ @output_string.should include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello2',N'monkey',NULL);")
513
+ @output_string.should_not include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello',N'kjhjd^&dkjh', N'aawefjkafe');")
514
+ @output_string.should_not include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello1',N'kjhj!', 892938);")
515
+ @output_string.should_not include("INSERT [dbo].[one_more_table] ([a], [password], [c], [d,d]) VALUES (N'hello2',N'moose!!', NULL);")
516
+ @output_string.should_not include("INSERT [dbo].[some_table] ([email], [name], [something], [age]) VALUES (N'bob@honk.com',N'bob', N'some''thin,ge())lse1', 25, CAST(0x00009E1A00000000 AS DATETIME));")
517
+ @output_string.should_not include("INSERT [dbo].[some_table] ([email], [name], [something], [age]) VALUES (N'joe@joe.com',N'joe', N'somethingelse2', 54, CAST(0x00009E1A00000000 AS DATETIME));")
518
+ end
519
+
520
+ it "honors a special case: on the people table, rows with anything@honk.com in a slot marked with :honk_email_skip do not change this slot" do
521
+ @output_string.should include("(N'bob@honk.com',")
522
+ @output_string.should include("(N'dontmurderme@direwolf.com',")
523
+ @output_string.should_not include("joe@joe.com")
524
+ end
525
+ end
526
+
527
+ context "when fail_on_unspecified_columns is set to true" do
528
+ before do
529
+ @database_dump = StringIO.new(<<-SQL)
530
+ INSERT INTO [dbo].[some_table] ([email], [name], [something], [age]) VALUES ('bob@honk.com','bob', 'some''thin,ge())lse1', 25);
531
+ SQL
532
+
533
+ @ddo = MyObfuscate.new({
534
+ :some_table => {
535
+ :email => {:type => :email, :skip_regexes => [/^[\w\.\_]+@honk\.com$/i, /^dontmurderme@direwolf.com$/]},
536
+ :name => {:type => :string, :length => 8, :chars => MyObfuscate::USERNAME_CHARS},
537
+ :age => {:type => :integer, :between => 10...80}
538
+ }
539
+ })
540
+ @ddo.database_type = :sql_server
541
+ @ddo.fail_on_unspecified_columns = true
542
+ end
543
+
544
+ it "should raise an exception when an unspecified column is found" do
545
+ lambda {
546
+ @ddo.obfuscate(@database_dump, StringIO.new)
547
+ }.should raise_error(/column 'something' defined/i)
548
+ end
549
+
550
+ it "should accept columns defined in globally_kept_columns" do
551
+ @ddo.globally_kept_columns = %w[something]
552
+ lambda {
553
+ @ddo.obfuscate(@database_dump, StringIO.new)
554
+ }.should_not raise_error
555
+ end
243
556
  end
244
557
  end
245
558
  end