testability-driver 0.9.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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