testability-driver 0.9.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_composition.rb +1 -1
  2. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_description.rb +11 -7
  3. data/lib/tdriver/base/behaviour/behaviours/object_composition.rb +8 -0
  4. data/lib/tdriver/base/behaviour/factory.rb +229 -209
  5. data/lib/tdriver/base/errors.rb +3 -0
  6. data/lib/tdriver/base/state_object.rb +11 -20
  7. data/lib/tdriver/base/sut/controller.rb +4 -4
  8. data/lib/tdriver/base/sut/factory.rb +205 -170
  9. data/lib/tdriver/base/sut/generic/behaviours/application.rb +256 -174
  10. data/lib/tdriver/base/sut/generic/behaviours/find.rb +17 -11
  11. data/lib/tdriver/base/sut/generic/behaviours/flash_behaviour.rb +57 -66
  12. data/lib/tdriver/base/sut/generic/behaviours/sut.rb +578 -497
  13. data/lib/tdriver/base/sut/generic/behaviours/switchbox_behaviour.rb +41 -15
  14. data/lib/tdriver/base/sut/generic/behaviours/verification.rb +48 -19
  15. data/lib/tdriver/base/sut/generic/commands/fixture.rb +47 -0
  16. data/lib/tdriver/base/sut/generic/commands/key_sequence.rb +25 -13
  17. data/lib/tdriver/base/sut/generic/commands/screen_capture.rb +16 -10
  18. data/lib/tdriver/base/sut/generic/plugin.rb +9 -3
  19. data/lib/tdriver/base/sut/sut.rb +41 -33
  20. data/lib/tdriver/base/test_object/abstract.rb +26 -3
  21. data/lib/tdriver/base/test_object/adapter.rb +399 -0
  22. data/lib/tdriver/base/test_object/behaviours/syncronization.rb +56 -14
  23. data/lib/tdriver/base/test_object/behaviours/test_object.rb +663 -197
  24. data/lib/tdriver/base/test_object/cache.rb +132 -0
  25. data/lib/tdriver/base/test_object/factory.rb +677 -426
  26. data/lib/tdriver/base/test_object/factory_new.rb +202 -0
  27. data/lib/tdriver/base/test_object/identificator.rb +24 -17
  28. data/lib/tdriver/base/test_object/loader.rb +9 -3
  29. data/lib/tdriver/base/test_object/verification.rb +181 -0
  30. data/lib/tdriver/loader.rb +1 -1
  31. data/lib/tdriver/report/report.rb +2 -0
  32. data/lib/tdriver/report/report_api.rb +4 -4
  33. data/lib/tdriver/report/report_creator.rb +29 -3
  34. data/lib/tdriver/report/report_data_presentation.rb +7 -3
  35. data/lib/tdriver/report/report_execution_statistics.rb +80 -21
  36. data/lib/tdriver/report/report_javascript.rb +192 -0
  37. data/lib/tdriver/report/report_test_case_run.rb +22 -0
  38. data/lib/tdriver/report/report_test_run.rb +62 -55
  39. data/lib/tdriver/report/report_writer.rb +57 -56
  40. data/lib/tdriver/tdriver.rb +14 -41
  41. data/lib/tdriver/util/common/error.rb +1 -0
  42. data/lib/tdriver/util/common/exceptions.rb +12 -0
  43. data/lib/tdriver/util/common/file.rb +12 -6
  44. data/lib/tdriver/util/common/gem.rb +2 -1
  45. data/lib/tdriver/util/common/hash.rb +152 -0
  46. data/lib/tdriver/util/common/kernel.rb +49 -34
  47. data/lib/tdriver/util/common/loader.rb +21 -17
  48. data/lib/tdriver/util/common/numeric.rb +39 -0
  49. data/lib/tdriver/util/common/object.rb +115 -0
  50. data/lib/tdriver/util/common/string.rb +55 -2
  51. data/lib/tdriver/util/dbaccess/dbaccess.rb +194 -161
  52. data/lib/tdriver/util/dynamic_attribute_filter.rb +6 -0
  53. data/lib/tdriver/util/hooking.rb +2 -2
  54. data/lib/tdriver/util/loader.rb +2 -2
  55. data/lib/tdriver/util/localisation/localisation.rb +277 -18
  56. data/lib/tdriver/util/logger.rb +142 -13
  57. data/lib/tdriver/util/parameter/parameter_hash.rb +8 -5
  58. data/lib/tdriver/util/parameter/parameter_xml.rb +18 -2
  59. data/lib/tdriver/util/recorder.rb +17 -12
  60. data/lib/tdriver/util/user_data/user_data.rb +3 -2
  61. data/lib/tdriver/util/{video_rec.rb → video_utils.rb} +136 -16
  62. data/lib/tdriver/util/xml/abstraction.rb +7 -0
  63. data/lib/tdriver/util/xml/attribute.rb +32 -0
  64. data/lib/tdriver/util/xml/loader.rb +8 -2
  65. data/lib/tdriver/util/xml/nil_node.rb +95 -0
  66. data/lib/tdriver/util/xml/parsers/nokogiri/abstraction.rb +46 -7
  67. data/lib/tdriver/util/xml/parsers/nokogiri/attribute.rb +19 -9
  68. data/lib/tdriver/util/xml/parsers/nokogiri/document.rb +1 -1
  69. data/lib/tdriver/util/xml/parsers/nokogiri/element.rb +13 -1
  70. data/lib/tdriver/util/xml/parsers/nokogiri/loader.rb +6 -0
  71. data/lib/tdriver/util/xml/parsers/nokogiri/nodeset.rb +27 -15
  72. data/lib/tdriver/util/xml/parsers/nokogiri/text.rb +57 -0
  73. data/lib/tdriver/util/xml/text.rb +32 -0
  74. data/lib/tdriver/util/xml/xml.rb +35 -22
  75. data/lib/tdriver/version.rb +1 -1
  76. data/lib/tdriver-devtools/behaviour/xml/rdoc_behaviour_xml_generator.rb +41 -34
  77. data/lib/tdriver-devtools/doc/generate.rb +31 -6
  78. data/lib/tdriver-devtools/doc/xslt/template.xsl +46 -25
  79. data/lib/tdriver-devtools/tests/feature_tests/example/behaviour_example.rb +100 -0
  80. data/lib/tdriver-devtools/tests/feature_tests/update +1 -1
  81. data/lib/tdriver.rb +0 -3
  82. data/xml/behaviours/generic.xml +1 -1
  83. data/xml/defaults/generic.xml +4 -90
  84. data/xml/templates/generic.xml +33 -25
  85. metadata +21 -29
  86. data/lib/tdriver-devtools/behaviour/xml_generator/example/flick-example.rb +0 -245
  87. data/lib/tdriver-devtools/behaviour/xml_generator/example/sut.rb +0 -964
  88. data/lib/tdriver-devtools/behaviour/xml_generator/generate.rb +0 -68
  89. data/lib/tdriver-devtools/behaviour/xml_generator/lib/custom_rdoc_generator.rb +0 -1865
  90. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.default.template +0 -1
  91. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.template +0 -3
  92. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument_type.template +0 -4
  93. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.exception.template +0 -4
  94. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.arguments.template +0 -4
  95. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.deprecated.template +0 -3
  96. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.exceptions.template +0 -3
  97. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.info.template +0 -1
  98. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.returns.template +0 -3
  99. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.tables.template +0 -3
  100. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.template +0 -12
  101. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.returns.template +0 -5
  102. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.item.template +0 -1
  103. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.row.template +0 -2
  104. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.template +0 -7
  105. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.template +0 -14
  106. data/lib/tdriver-devtools/behaviour/xml_generator/update +0 -3
  107. data/lib/tdriver-devtools/tests/feature_tests/example/flick-example.rb +0 -233
  108. data/lib/tdriver-devtools/tests/feature_tests/example/impl.rb +0 -194
@@ -20,20 +20,24 @@
20
20
  require 'rbconfig' # ??
21
21
 
22
22
  # common modules - should be generic and runnable as standalone
23
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'error.rb' ) )
24
-
25
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'array.rb' ) )
26
-
27
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'crc16.rb' ) )
28
-
29
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'environment.rb' ) )
30
-
31
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'file.rb' ) )
32
-
33
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'gem.rb' ) )
34
-
35
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'kernel.rb' ) )
36
-
37
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'retryable.rb' ) )
38
-
39
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'string.rb' ) )
23
+ [
24
+ # Ruby object extensions
25
+ 'object.rb',
26
+ 'numeric.rb',
27
+ 'hash.rb',
28
+ 'string.rb',
29
+
30
+ 'exceptions.rb',
31
+ 'error.rb', # TODO: move custom exceptions to exceptions.rb
32
+
33
+ 'array.rb',
34
+ 'crc16.rb',
35
+ 'environment.rb',
36
+ 'file.rb',
37
+ 'gem.rb',
38
+ 'kernel.rb',
39
+ 'retryable.rb' ].each{ | filename |
40
+
41
+ require File.expand_path( File.join( File.dirname( __FILE__ ), filename ) )
42
+
43
+ }
@@ -0,0 +1,39 @@
1
+ ############################################################################
2
+ ##
3
+ ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
+ ## All rights reserved.
5
+ ## Contact: Nokia Corporation (testabilitydriver@nokia.com)
6
+ ##
7
+ ## This file is part of Testability Driver.
8
+ ##
9
+ ## If you have questions regarding the use of this file, please contact
10
+ ## Nokia at testabilitydriver@nokia.com .
11
+ ##
12
+ ## This library is free software; you can redistribute it and/or
13
+ ## modify it under the terms of the GNU Lesser General Public
14
+ ## License version 2.1 as published by the Free Software Foundation
15
+ ## and appearing in the file LICENSE.LGPL included in the packaging
16
+ ## of this file.
17
+ ##
18
+ ############################################################################
19
+
20
+ # extend Ruby Numeric class functionality
21
+ class Numeric
22
+
23
+ def positive?
24
+ self > 0
25
+ end
26
+
27
+ def non_negative?
28
+ self >= 0
29
+ end
30
+
31
+ def non_positive?
32
+ self <= 0
33
+ end
34
+
35
+ def negative?
36
+ self < 0
37
+ end
38
+
39
+ end
@@ -0,0 +1,115 @@
1
+ ############################################################################
2
+ ##
3
+ ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
+ ## All rights reserved.
5
+ ## Contact: Nokia Corporation (testabilitydriver@nokia.com)
6
+ ##
7
+ ## This file is part of Testability Driver.
8
+ ##
9
+ ## If you have questions regarding the use of this file, please contact
10
+ ## Nokia at testabilitydriver@nokia.com .
11
+ ##
12
+ ## This library is free software; you can redistribute it and/or
13
+ ## modify it under the terms of the GNU Lesser General Public
14
+ ## License version 2.1 as published by the Free Software Foundation
15
+ ## and appearing in the file LICENSE.LGPL included in the packaging
16
+ ## of this file.
17
+ ##
18
+ ############################################################################
19
+
20
+ # extend Ruby Object class functionality
21
+ class Object
22
+
23
+ # define method to class instance
24
+ def meta_def method_name, &block
25
+
26
+ ( class << self; self; end ).instance_eval{ define_method method_name, &block }
27
+
28
+ end
29
+
30
+ # Compare receiver object type with given types. Raises exception is class name does not equal.
31
+ def check_type( types, message = "wrong argument type $1 (expected $2)" )
32
+
33
+ # raise exception if message is not type of String
34
+ raise TypeError.new( "wrong argument type %s for message (expected String)" % [ message.class ] ) unless message.kind_of?( String )
35
+
36
+ # create array of types
37
+ type_array = types.kind_of?( Array ) ? types : [ types ]
38
+
39
+ # default result value
40
+ found = false
41
+
42
+ # collect verbose type list
43
+ verbose_type_list = type_array.each_with_index.collect{ | type, index |
44
+
45
+ raise TypeError.new( "invalid argument type #{ type } for check_type. Did you mean #{ type.class }?" ) unless type.kind_of?( Class )
46
+
47
+ found = true if self.kind_of?( type )
48
+
49
+ # result string, separate types if multiple types given
50
+ "#{ ( ( index > 0 ) ? ( index + 1 < type_array.count ? ", " : " or " ) : "" ) }#{ type.to_s }"
51
+
52
+ }.join
53
+
54
+ # raise exception if type did not match
55
+ unless found
56
+
57
+ # convert macros
58
+ [ self.class, verbose_type_list, self.inspect ].each_with_index{ | param, index | message.gsub!( "$#{ index + 1 }", param.to_s ) }
59
+
60
+ # raise the exception
61
+ raise TypeError.new( message )
62
+
63
+ end
64
+
65
+ # pass self as return value
66
+ self
67
+
68
+ end
69
+
70
+ def not_nil( message = "Value must not be nil", exception = ArgumentError )
71
+
72
+ raise exception.new( message ) if self.nil?
73
+
74
+ end
75
+
76
+ def validate( values, message = "Unexpected value $3 for $1 (expected $2)" )
77
+
78
+ # raise exception if message is not type of String
79
+ raise TypeError.new( "wrong argument type %s for message (expected String)" % [ message.class ] ) unless message.kind_of?( String )
80
+
81
+ # create array of values
82
+ values_array = values.kind_of?( Array ) ? values : [ values ]
83
+
84
+ # default result value
85
+ found = false
86
+
87
+ # collect verbose type list
88
+ verbose_values_list = values_array.each_with_index.collect{ | value, index |
89
+
90
+ raise TypeError.new( "Invalid argument type #{ value.class } for value (expected #{ self.class })" ) unless value.kind_of?( self.class )
91
+
92
+ found = true if self == value
93
+
94
+ # result string, separate types if multiple types given
95
+ "#{ ( ( index > 0 ) ? ( index + 1 < values_array.count ? ", " : " or " ) : "" ) }#{ value.inspect }"
96
+
97
+ }.join
98
+
99
+ # raise exception if value was not found
100
+ unless found
101
+
102
+ # convert macros
103
+ [ self.class, verbose_values_list, self.inspect ].each_with_index{ | param, index | message.gsub!( "$#{ index + 1 }", param.to_s ) }
104
+
105
+ # raise the exception
106
+ raise ArgumentError.new( message )
107
+
108
+ end
109
+
110
+ # pass self as return value
111
+ self
112
+
113
+ end
114
+
115
+ end
@@ -17,6 +17,58 @@
17
17
  ##
18
18
  ############################################################################
19
19
 
20
+ class String
21
+
22
+ def not_empty( message = "String must not be empty", exception = ArgumentError )
23
+
24
+ raise exception.new( message ) if self.empty?
25
+
26
+ end
27
+
28
+ # Function determines if string is "true" or "false"
29
+ # == params
30
+ # string:: String
31
+ # == returns
32
+ # TrueClass/FalseClass
33
+ def boolean?
34
+
35
+ /^(true|false)$/i.match( self ).kind_of?( MatchData )
36
+
37
+ end
38
+
39
+ # Function determines if string is numeric
40
+ # == params
41
+ # string:: Numeric string
42
+ # == returns
43
+ # TrueClass/FalseClass
44
+ def numeric?
45
+
46
+ /^[0-9]+$/.match( self ).kind_of?( MatchData )
47
+
48
+ end
49
+
50
+ # Function converts "true" or "false" to boolean
51
+ # == params
52
+ # string:: String
53
+ # == returns
54
+ # TrueClass/FalseClass
55
+ def to_boolean
56
+
57
+ if /^(true|false)$/i.match( self.to_s )
58
+
59
+ $1.downcase == 'true'
60
+
61
+ else
62
+
63
+ #default
64
+ Kernel::raise TypeError.new( "Unable to convert string \"#{ self }\" to boolean (Expected \”true\" or \"false\")" )
65
+
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
20
72
  module MobyUtil
21
73
 
22
74
  class StringHelper
@@ -29,7 +81,8 @@ module MobyUtil
29
81
  def self.boolean?( string )
30
82
 
31
83
  # raise exception if argument type other than String
32
- Kernel::raise ArgumentError.new("Invalid argument format %s (Expected: %s)" % [ string.class, "String" ]) unless string.kind_of?( String )
84
+ #Kernel::raise ArgumentError.new("Invalid argument format %s (Expected: %s)" % [ string.class, "String" ]) unless string.kind_of?( String )
85
+ string.check_type( String, "Wrong argument type $1 (Expected $2)" )
33
86
 
34
87
  /^(true|false)$/i.match( string ).kind_of?( MatchData )
35
88
 
@@ -46,7 +99,7 @@ module MobyUtil
46
99
 
47
100
  Kernel::raise ArgumentError.new("Invalid argument format %s (Expected: %s)" % [ string.class, "String" ]) unless string.kind_of?( String )
48
101
 
49
- /[0-9]+/.match( string ).kind_of?( MatchData )
102
+ /^[0-9]+$/.match( string ).kind_of?( MatchData )
50
103
 
51
104
  end
52
105
 
@@ -18,171 +18,204 @@
18
18
  ############################################################################
19
19
 
20
20
  # Utility for handling database connections
21
-
22
21
  module MobyUtil
23
22
 
24
- class DBAccess
23
+ class DBAccess
25
24
 
26
25
  DB_TYPE_MYSQL = 'mysql'
27
26
  DB_TYPE_SQLITE = 'sqlite'
28
27
 
29
- include Singleton
30
-
31
- # == description
32
- # Initialize the singleton
33
- # connection is maintained as long as the connectivity parameters remain the same
34
- # this is to avoid constant connect as this takes time
35
- #
36
- def initialize
37
- @@_connections = {}
38
- @@_mysql = nil
39
- end
40
-
41
- # == description
42
- # Class Method that returns existing connections
43
- #
44
- def DBAccess.connections()
45
- return @@_connections
46
- end
47
-
48
- # == description
49
- # Runs an SQL query on the on the given MobyUtil::DBConnection
50
- #
51
- # == arguments
52
- # dbc
53
- # MobyUtil::DBConnection
54
- # description: object with the connection details of an open sql connection
55
- #
56
- # query_string
57
- # String
58
- # description: database-specific SQL query (note that mysql and sqlite have slightly different syntax)
59
- # example: "select * from tdriver_locale;"
60
- #
61
- # == returns
62
- # Array
63
- # description: Array of rows returned by the server. Each row is an array of String values.
64
- #
65
- # == throws
66
- # ArgumentError
67
- # description: if the argument provided is not the right object type
68
- #
69
- def self.query( dbc, query_string )
70
- # Create first instance of this class if it doesn't exist
71
- self.instance
72
-
73
- raise ArgumentError.new("Invalid connection object provided.") if dbc.nil? or !dbc.kind_of? MobyUtil::DBConnection
74
-
75
- db_type = dbc.db_type
76
- host = dbc.host
77
- username = dbc.username
78
- password = dbc.password
79
- database_name = dbc.database_name
80
-
81
- # Check creation parameters
82
- raise DbTypeNotDefinedError.new( "Database type need to be either 'mysql' or 'sqlite'!" ) if db_type == nil
83
- raise DbTypeNotSupportedError.new( "Database type '#{db_type}' not supported! Type need to be either 'mysql' or 'sqlite'!" ) unless db_type == DB_TYPE_MYSQL or db_type == DB_TYPE_SQLITE
84
- if db_type == DB_TYPE_MYSQL
85
- raise ArgumentError.new("Host must be provided as a non empty string.") if host.nil? or host.class != String or host.empty?
86
- raise ArgumentError.new("Username must be provided as a non empty string.") if username.nil? or username.class != String or username.empty?
87
- raise ArgumentError.new("Password must be provided as a string.") if password.nil? or password.class != String
88
- end
89
- raise ArgumentError.new("The database name must be provided as a non empty string.") if database_name.nil? or database_name.class != String or database_name.empty?
90
- raise ArgumentError.new("The query qtring must be provided as a non empty string.") if query_string.nil? or query_string.class != String or query_string.empty?
91
-
92
- # Check for exsting connection for that host and create it if needed
93
- if !@@_connections.has_key?( host + db_type + database_name ) # make connection ID unique by using host, type and db on the key
94
- dbc.dbh = connect_db( db_type, host, username, password, database_name )
95
- @@_connections[ host + db_type + database_name ] = dbc
96
- end
97
-
98
- if db_type == DB_TYPE_MYSQL
99
- query_result = @@_connections[ host + db_type + database_name ].dbh.query( query_string )
100
- elsif dbc.db_type == DB_TYPE_SQLITE
101
- query_result = @@_connections[ host + db_type + database_name ].dbh.query( query_string )
102
- end
103
-
104
- # Return a uniform set of results as an array of rows, rows beeing an array of values ( Array<Array<String>> )
105
- result = Array.new
106
- if db_type == DB_TYPE_MYSQL and !query_result.nil?
107
- query_result.num_rows.times do |i|
108
- result << query_result.fetch_row
109
- end
110
- elsif db_type == DB_TYPE_SQLITE and !query_result.nil?
111
- # Create Array<SQLite3::ResultSet::ArrayWithTypesAndFields<String>> type result
112
- # it effectively behaves the same as with Array<Array<String>> but the inner Arrays have .fields and .types properties
113
- # which return the column name and type for each value on the row (Array) returned.
114
- while ( row = query_result.next )
115
- result << row
116
- end
117
- # it is essentially a prepare method so we need to call close to free the connection
118
- query_result.close
119
- end
120
- return result
121
- end
122
-
123
- # == description
124
- # Retunrs the number of affected rows on the latest sql query on the given MobyUtil::DBConnection
125
- #
126
- # == arguments
127
- # dbc
128
- # MobyUtil::DBConnection
129
- # description: object with the connection details of an open sql connection
130
- #
131
- # == returns
132
- # Integer
133
- # description: number of rows affected
134
- #
135
- # == throws
136
- # ArgumentError
137
- # description: if the argument provided is not the right object type
138
- #
139
- def self.affected_rows(dbc)
140
- raise ArgumentError.new("Invalid connection object provided.") if dbc.nil? or !dbc.kind_of? MobyUtil::DBConnection
141
-
142
- # Check for exsting connection for that host and create it if needed
143
- if !@@_connections.has_key?( dbc.host + dbc.db_type + dbc.database_name ) # make connection ID unique by using host, type and db on the key
144
- dbc.dbh = connect_db( dbc.db_type, dbc.host, dbc.username, dbc.password, dbc.database_name )
145
- @@_connections[ dbc.host + dbc.db_type + dbc.database_name ] = dbc
146
- end
147
- result = 0
148
- if dbc.db_type == DB_TYPE_MYSQL
149
- result = @@_connections[ dbc.host + dbc.db_type + dbc.database_name ].dbh.affected_rows
150
- elsif dbc.db_type == DB_TYPE_SQLITE
151
- result = @@_connections[ dbc.host + dbc.db_type + dbc.database_name ].dbh.changes
152
- end
153
- return result
154
- end
155
-
156
-
157
-
158
- private
159
-
160
- # == description
161
- # Function establishes a new connection to as sql server and returns it's handle
162
- #
163
- def self.connect_db( db_type, host, username, password, database_name )
164
-
165
- # if mysql API and connection are not initialized, then initialize the mysql API
166
- if ( db_type == DB_TYPE_MYSQL ) && ( @@_mysql.nil? )
167
- require 'mysql'
168
- @@_mysql = Mysql::init
169
- elsif db_type == DB_TYPE_SQLITE
170
- require 'sqlite3'
171
- end
172
-
173
- begin
174
- dbh = @@_mysql.connect( host, username, password, database_name) if db_type == DB_TYPE_MYSQL
175
- dbh.query 'SET NAMES utf8' if db_type == DB_TYPE_MYSQL # set the utf8 encoding
176
- dbh = SQLite3::Database.new( database_name ) if db_type == DB_TYPE_SQLITE
177
- rescue
178
- raise SqlConnectError.new( $!.message )
179
- end
180
-
181
- return dbh
182
-
183
- end
184
-
185
- end # class
186
-
187
- end # module
28
+ include Singleton
29
+
30
+ # == description
31
+ # Initialize the singleton
32
+ # connection is maintained as long as the connectivity parameters remain the same
33
+ # this is to avoid constant connect as this takes time
34
+ #
35
+ def initialize
36
+ @@_connections = {}
37
+ @@_mysql = nil
38
+ end
39
+
40
+ # == description
41
+ # Class Method that returns existing connections
42
+ #
43
+ def DBAccess.connections()
44
+ return @@_connections
45
+ end
46
+
47
+ # == description
48
+ # Runs an SQL query on the on the given MobyUtil::DBConnection
49
+ #
50
+ # == arguments
51
+ # dbc
52
+ # MobyUtil::DBConnection
53
+ # description: object with the connection details of an open sql connection
54
+ #
55
+ # query_string
56
+ # String
57
+ # description: database-specific SQL query (note that mysql and sqlite have slightly different syntax)
58
+ # example: "select * from tdriver_locale;"
59
+ #
60
+ # == returns
61
+ # Array
62
+ # description: Array of rows returned by the server. Each row is an array of String values.
63
+ #
64
+ # == throws
65
+ # ArgumentError
66
+ # description: if the argument provided is not the right object type
67
+ #
68
+ def self.query( dbc, query_string )
69
+ # Create first instance of this class if it doesn't exist
70
+ self.instance
71
+
72
+ #raise ArgumentError.new("Invalid connection object provided.") if dbc.nil? or !dbc.kind_of? MobyUtil::DBConnection
73
+ dbc.check_type( MobyUtil::DBConnection, "Wrong argument type $1 for database connection object (expected $2)" )
74
+
75
+ #raise ArgumentError.new("The query qtring must be provided as a non empty string.") if query_string.nil? or query_string.class != String or query_string.empty?
76
+ query_string.check_type( String, "Wrong variable type $1 for database query string (expected $2)")
77
+ query_string.not_empty( "Database query string must not be empty string" )
78
+
79
+ db_type = dbc.db_type
80
+ host = dbc.host
81
+ username = dbc.username
82
+ password = dbc.password
83
+ database_name = dbc.database_name
84
+
85
+ # Check creation parameters
86
+
87
+ #raise DbTypeNotDefinedError.new( "Database type need to be either 'mysql' or 'sqlite'!" ) if db_type == nil
88
+ db_type.check_type( String, "Wrong argument type $1 for database type (expected $2)" )
89
+
90
+ #raise DbTypeNotSupportedError.new( "Database type '#{db_type}' not supported! Type need to be either 'mysql' or 'sqlite'!" ) unless db_type == DB_TYPE_MYSQL or db_type == DB_TYPE_SQLITE
91
+ db_type.validate( [ DB_TYPE_MYSQL, DB_TYPE_SQLITE ], "Unsupported database type $1 (expected $2)" )
92
+
93
+ if ( db_type == DB_TYPE_MYSQL )
94
+
95
+ # raise ArgumentError.new("Host must be provided as a non empty string.") if host.nil? or host.class != String or host.empty?
96
+ host.check_type( String, "Wrong variable type $1 for host (expected $2)" )
97
+ host.not_empty( "Host must not be empty string" )
98
+
99
+ #raise ArgumentError.new("Username must be provided as a non empty string.") if username.nil? or username.class != String or username.empty?
100
+ username.check_type( String, "Wrong variable type $1 for username (expected $2)" )
101
+ username.not_empty( "Username must not be empty string" )
102
+
103
+ #raise ArgumentError.new("Password must be provided as a string.") if password.nil? or password.class != String
104
+ password.check_type( String, "Wrong variable type $1 for password (expected $2)")
105
+
106
+ end
107
+
108
+ #raise ArgumentError.new("The database name must be provided as a non empty string.") if database_name.nil? or database_name.class != String or database_name.empty?
109
+ database_name.check_type( String, "Wrong variable type $1 for database name (expected $2)" )
110
+ database_name.not_empty( "Database name must not be empty string" )
111
+
112
+ # Check for exsting connection for that host and create it if needed
113
+ if !@@_connections.has_key?( host + db_type + database_name ) # make connection ID unique by using host, type and db on the key
114
+ dbc.dbh = connect_db( db_type, host, username, password, database_name )
115
+ @@_connections[ host + db_type + database_name ] = dbc
116
+ end
117
+
118
+ if db_type == DB_TYPE_MYSQL
119
+
120
+ query_result = @@_connections[ host + db_type + database_name ].dbh.query( query_string ) # identical?
121
+
122
+ elsif dbc.db_type == DB_TYPE_SQLITE
123
+
124
+ query_result = @@_connections[ host + db_type + database_name ].dbh.query( query_string ) # identical?
125
+
126
+ end
127
+
128
+ # Return a uniform set of results as an array of rows, rows beeing an array of values ( Array<Array<String>> )
129
+ result = []
130
+
131
+ if db_type == DB_TYPE_MYSQL and !query_result.nil?
132
+
133
+ query_result.num_rows.times do |i|
134
+
135
+ result << query_result.fetch_row
136
+
137
+ end
138
+
139
+ elsif db_type == DB_TYPE_SQLITE and !query_result.nil?
140
+
141
+ # Create Array<SQLite3::ResultSet::ArrayWithTypesAndFields<String>> type result
142
+ # it effectively behaves the same as with Array<Array<String>> but the inner Arrays have .fields and .types properties
143
+ # which return the column name and type for each value on the row (Array) returned.
144
+ while ( row = query_result.next )
145
+ result << row
146
+ end
147
+
148
+ # it is essentially a prepare method so we need to call close to free the connection
149
+ query_result.close
150
+
151
+ end
152
+
153
+ result
154
+
155
+ end
156
+
157
+ # == description
158
+ # Retunrs the number of affected rows on the latest sql query on the given MobyUtil::DBConnection
159
+ #
160
+ # == arguments
161
+ # dbc
162
+ # MobyUtil::DBConnection
163
+ # description: object with the connection details of an open sql connection
164
+ #
165
+ # == returns
166
+ # Integer
167
+ # description: number of rows affected
168
+ #
169
+ # == throws
170
+ # ArgumentError
171
+ # description: if the argument provided is not the right object type
172
+ #
173
+ def self.affected_rows(dbc)
174
+
175
+ #raise ArgumentError.new("Invalid connection object provided.") if dbc.nil? or !dbc.kind_of? MobyUtil::DBConnection
176
+ dbc.check_type( MobyUtil::DBConnection, "Wrong argument type $1 for database connection object (expected $2)" )
177
+
178
+ # Check for exsting connection for that host and create it if needed
179
+ if !@@_connections.has_key?( dbc.host + dbc.db_type + dbc.database_name ) # make connection ID unique by using host, type and db on the key
180
+ dbc.dbh = connect_db( dbc.db_type, dbc.host, dbc.username, dbc.password, dbc.database_name )
181
+ @@_connections[ dbc.host + dbc.db_type + dbc.database_name ] = dbc
182
+ end
183
+ result = 0
184
+ if dbc.db_type == DB_TYPE_MYSQL
185
+ result = @@_connections[ dbc.host + dbc.db_type + dbc.database_name ].dbh.affected_rows
186
+ elsif dbc.db_type == DB_TYPE_SQLITE
187
+ result = @@_connections[ dbc.host + dbc.db_type + dbc.database_name ].dbh.changes
188
+ end
189
+ return result
190
+ end
191
+
192
+ private
193
+
194
+ # == description
195
+ # Function establishes a new connection to as sql server and returns it's handle
196
+ #
197
+ def self.connect_db( db_type, host, username, password, database_name )
198
+
199
+ # if mysql API and connection are not initialized, then initialize the mysql API
200
+ if ( db_type == DB_TYPE_MYSQL ) && ( @@_mysql.nil? )
201
+ require 'mysql'
202
+ @@_mysql = Mysql::init
203
+ elsif db_type == DB_TYPE_SQLITE
204
+ require 'sqlite3'
205
+ end
206
+
207
+ begin
208
+ dbh = @@_mysql.connect( host, username, password, database_name) if db_type == DB_TYPE_MYSQL
209
+ dbh.query 'SET NAMES utf8' if db_type == DB_TYPE_MYSQL # set the utf8 encoding
210
+ dbh = SQLite3::Database.new( database_name ) if db_type == DB_TYPE_SQLITE
211
+ rescue
212
+ raise SqlConnectError.new( $!.message )
213
+ end
214
+
215
+ return dbh
216
+
217
+ end
218
+
219
+ end # DBAccess
188
220
 
221
+ end # MobyUtil