dftcc 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/dftcc +33 -0
- data/bin/setup +7 -0
- data/dftcc.gemspec +24 -0
- data/lib/AnalysisHTMLFile.rb +61 -0
- data/lib/AnalyzedClass.rb +240 -0
- data/lib/AnalyzedClassGenerator.rb +225 -0
- data/lib/ClassAnalyzer.rb +72 -0
- data/lib/FormGenerator.rb +142 -0
- data/lib/IndexHTMLFile.rb +177 -0
- data/lib/LineDeterminator.rb +47 -0
- data/lib/dftcc/version.rb +3 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d91d7f550f49be85bc9e0dbb47ad22d290870c80
|
4
|
+
data.tar.gz: 793c01e8812c794e5cd5d270557ff4ed8bd9a205
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f7392ad95fee2cc8d1562335efa93e876de38670796188ddc1a5e5d0afaac840a97dbcee6b31058dc1b8cf2d62f5e284554b35030e572d606b17abd26081df0
|
7
|
+
data.tar.gz: 8ea9570f8b8db58f46522c463c96b281e298b68624931ce9fb2c8c0fec9ce9bfdb934ef9cec5eca1b55325b99e3ec62325a2c97cccfe3e2cf2859e0052b3d15f
|
data/.gitignore
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Christopher Morris
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Dftcc
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/dftcc`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'dftcc'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install dftcc
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/[my-github-username]/dftcc/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "dftcc"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/dftcc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'commander/import'
|
5
|
+
|
6
|
+
require_relative '../lib/ClassAnalyzer'
|
7
|
+
|
8
|
+
program :version, '0.0.2'
|
9
|
+
program :description, 'Swift Code Coverage Static Analyzer'
|
10
|
+
|
11
|
+
command :gen do |c|
|
12
|
+
c.syntax = 'dftcc gen directory/with/Swift/files [--output <outputdirectory>]'
|
13
|
+
c.summary = 'Generates analysis report of code coverage'
|
14
|
+
c.description = 'Generates analysis report of code coverage.'
|
15
|
+
c.option '--output PATH', 'Optional output directory'
|
16
|
+
c.action do |args, options|
|
17
|
+
if args.count < 2
|
18
|
+
say_error "You must provide the directory of Swift files to analyze:"
|
19
|
+
say_error "\t dftsg gen directory/with/Swift/files"
|
20
|
+
elsif args.count > 2
|
21
|
+
say_error "If you want to select an output directory, use the --output command"
|
22
|
+
say_error "\t dftsg gen directory/with/Swift/files --output my/output/directory"
|
23
|
+
elsif args.count == 2
|
24
|
+
input = args.first
|
25
|
+
inputTest = args[1]
|
26
|
+
output = options.output
|
27
|
+
|
28
|
+
analyzer = ClassAnalyzer.new(input, inputTest, output)
|
29
|
+
analyzer.analyze
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/bin/setup
ADDED
data/dftcc.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dftcc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dftcc"
|
8
|
+
spec.version = Dftcc::VERSION
|
9
|
+
spec.authors = ["Christopher Morris"]
|
10
|
+
spec.email = ["majorent@icloud.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Generates analysis report of code coverage}
|
13
|
+
spec.description = %q{Generates analysis report of code coverage}
|
14
|
+
spec.homepage = "http://rubygems.org"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'AnalyzedClass'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
class AnalysisHTMLFile
|
8
|
+
def initialize (directory, analyzedClass)
|
9
|
+
@directory = directory
|
10
|
+
@analyzedClass = analyzedClass
|
11
|
+
@name = @analyzedClass.fileName.gsub("#{File.dirname(@analyzedClass.fileName)}", "").gsub("/", "")
|
12
|
+
end
|
13
|
+
|
14
|
+
def writeFile
|
15
|
+
FileUtils::mkdir_p "#{@directory}"
|
16
|
+
@fileHtml = File.new("#{@directory}/#{@name}.html", "w+")
|
17
|
+
@fileHtml.puts "<HTML><BODY>"
|
18
|
+
@fileHtml.puts "<pre>"
|
19
|
+
|
20
|
+
funcCurlyBraces = 0
|
21
|
+
isInFunction = false
|
22
|
+
puts @analyzedClass.fileName
|
23
|
+
f = File.open(@analyzedClass.fileName, "r")
|
24
|
+
f.each_line do |line|
|
25
|
+
if @analyzedClass.isLineWithTestedFunction line
|
26
|
+
isInFunction = true
|
27
|
+
end
|
28
|
+
|
29
|
+
if isInFunction
|
30
|
+
if line.include? "{"
|
31
|
+
funcCurlyBraces += 1
|
32
|
+
end
|
33
|
+
if line.include? "}"
|
34
|
+
funcCurlyBraces -= 1
|
35
|
+
end
|
36
|
+
|
37
|
+
@fileHtml.puts "<font size=\"3\" color=\"#52CC52\">#{line.chomp}</font>"
|
38
|
+
|
39
|
+
if funcCurlyBraces == 0
|
40
|
+
isInFunction = false
|
41
|
+
end
|
42
|
+
else
|
43
|
+
@fileHtml.puts "<code>#{line.chomp}</code>"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
f.close
|
47
|
+
|
48
|
+
@fileHtml.puts "</pre>"
|
49
|
+
@fileHtml.puts "</BODY></HTML>"
|
50
|
+
@fileHtml.close()
|
51
|
+
end
|
52
|
+
|
53
|
+
def directory
|
54
|
+
@directory
|
55
|
+
end
|
56
|
+
|
57
|
+
def name
|
58
|
+
@name
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class AnalyzedClass
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@functions = Array.new
|
7
|
+
@variables = Array.new
|
8
|
+
@testedFunctions = Array.new
|
9
|
+
@numberOfLines = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def addFunction (name, numLines)
|
13
|
+
@functions.push(Function.new(name, numLines))
|
14
|
+
end
|
15
|
+
|
16
|
+
def addVariable variable
|
17
|
+
@variables.push(variable)
|
18
|
+
end
|
19
|
+
|
20
|
+
def addTestedFunction function
|
21
|
+
if !(isTestedFunctionInArray function.name)
|
22
|
+
@testedFunctions.push(function)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def isTestedFunctionInArray functionName
|
27
|
+
for function in @testedFunctions
|
28
|
+
if function.name == functionName
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
|
35
|
+
def isLineWithTestedFunction line
|
36
|
+
for function in @testedFunctions
|
37
|
+
if line.include? function.name
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
def functions
|
45
|
+
@functions
|
46
|
+
end
|
47
|
+
|
48
|
+
def variables
|
49
|
+
@variables
|
50
|
+
end
|
51
|
+
|
52
|
+
def testedFunctions
|
53
|
+
@testedFunctions
|
54
|
+
end
|
55
|
+
|
56
|
+
def name
|
57
|
+
@name
|
58
|
+
end
|
59
|
+
|
60
|
+
def numberOfLines=(numberOfLines)
|
61
|
+
@numberOfLines = numberOfLines
|
62
|
+
end
|
63
|
+
|
64
|
+
def numberOfLines
|
65
|
+
@numberOfLines
|
66
|
+
end
|
67
|
+
|
68
|
+
def numberOfLinesTested
|
69
|
+
count = 0
|
70
|
+
for function in @testedFunctions
|
71
|
+
count += function.numLines
|
72
|
+
end
|
73
|
+
return count
|
74
|
+
end
|
75
|
+
|
76
|
+
def name=(name)
|
77
|
+
name = name.strip
|
78
|
+
@name = name
|
79
|
+
end
|
80
|
+
|
81
|
+
def fileName
|
82
|
+
@fileName
|
83
|
+
end
|
84
|
+
|
85
|
+
def fileName=(fileName)
|
86
|
+
@fileName = fileName
|
87
|
+
end
|
88
|
+
|
89
|
+
def variablesWithType
|
90
|
+
varsWithType = Array.new
|
91
|
+
for vari in @variables
|
92
|
+
if vari.type != nil
|
93
|
+
varsWithType.push(vari)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
return varsWithType
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Function
|
101
|
+
def initialize (name, numLines)
|
102
|
+
@name = name
|
103
|
+
@numLines = numLines
|
104
|
+
end
|
105
|
+
|
106
|
+
def name
|
107
|
+
@name
|
108
|
+
end
|
109
|
+
|
110
|
+
def numLines
|
111
|
+
@numLines
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class Variable
|
116
|
+
def initialize (keyword="", name="", type="")
|
117
|
+
@keyword = keyword
|
118
|
+
@name = name
|
119
|
+
@type = type
|
120
|
+
end
|
121
|
+
|
122
|
+
def name
|
123
|
+
@name
|
124
|
+
end
|
125
|
+
|
126
|
+
def type
|
127
|
+
@type
|
128
|
+
end
|
129
|
+
|
130
|
+
def keyword
|
131
|
+
@keyword
|
132
|
+
end
|
133
|
+
|
134
|
+
def variableForLine (line)
|
135
|
+
if !(line.include? "let ") and !(line.include? "var ")
|
136
|
+
return nil
|
137
|
+
end
|
138
|
+
|
139
|
+
index = beginningIndex line
|
140
|
+
variableKeyword = variableKeyword line
|
141
|
+
varName = variableName index, line
|
142
|
+
type = variableType line, varName
|
143
|
+
|
144
|
+
return Variable.new variableKeyword, varName, type
|
145
|
+
end
|
146
|
+
|
147
|
+
def variableType (line, variableName)
|
148
|
+
if variableName == nil or line.include? "["
|
149
|
+
return nil
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
if (line.include? "=" and line.include? "(")
|
154
|
+
|
155
|
+
if line.include? "."
|
156
|
+
indexDot = line.index(".")
|
157
|
+
indexParen = line.index("(")
|
158
|
+
if indexParen < indexDot
|
159
|
+
index = line.index("=")
|
160
|
+
temp = line[index+1..-1]
|
161
|
+
temp = temp.strip
|
162
|
+
temp = temp.slice(0..(temp.index("(") - 1)).strip
|
163
|
+
if temp.index("(") != 0
|
164
|
+
type = temp.strip
|
165
|
+
return type
|
166
|
+
end
|
167
|
+
end
|
168
|
+
else
|
169
|
+
index = line.index("=")
|
170
|
+
temp = line[index+1..-1]
|
171
|
+
type = temp.slice(0..(temp.index("(") - 1)).strip
|
172
|
+
return type
|
173
|
+
end
|
174
|
+
|
175
|
+
elsif line.include? ":"
|
176
|
+
index = line.index(":")
|
177
|
+
temp = line[index+1..-1].strip
|
178
|
+
if temp.include? "!"
|
179
|
+
temp = temp[0..-2]
|
180
|
+
end
|
181
|
+
|
182
|
+
if temp.include? "?"
|
183
|
+
temp = temp[0..-2]
|
184
|
+
end
|
185
|
+
|
186
|
+
if temp.include? "]"
|
187
|
+
temp = temp[0..temp.index("]")]
|
188
|
+
end
|
189
|
+
|
190
|
+
if temp.include? " "
|
191
|
+
temp = temp[0..temp.index(" ")]
|
192
|
+
end
|
193
|
+
return temp
|
194
|
+
end
|
195
|
+
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
|
199
|
+
def beginningIndex (line)
|
200
|
+
index = 0
|
201
|
+
if line.include? "var "
|
202
|
+
index = (line.index("var ") + 4)
|
203
|
+
elsif line.include? "let "
|
204
|
+
index = (line.index("let ") + 4)
|
205
|
+
end
|
206
|
+
return index
|
207
|
+
end
|
208
|
+
|
209
|
+
def variableKeyword (line)
|
210
|
+
if line.include? "var "
|
211
|
+
return "var"
|
212
|
+
end
|
213
|
+
return "let"
|
214
|
+
end
|
215
|
+
|
216
|
+
def variableName (index, line)
|
217
|
+
varName = ""
|
218
|
+
if line.include? ":" and !(line.include? "=")
|
219
|
+
varName = line.slice(index..(line.index(":")-1))
|
220
|
+
elsif
|
221
|
+
temp = line
|
222
|
+
temp = temp[index..-1]
|
223
|
+
whiteSpaceIndex = temp.index(" ")
|
224
|
+
equalsIndex = temp.index("=")
|
225
|
+
if equalsIndex == nil
|
226
|
+
equalsIndex = 9999
|
227
|
+
end
|
228
|
+
colonIndex = temp.index(":")
|
229
|
+
endStringSliceIndex = whiteSpaceIndex
|
230
|
+
if whiteSpaceIndex > equalsIndex
|
231
|
+
endStringSliceIndex = equalsIndex
|
232
|
+
end
|
233
|
+
varName = temp.slice(0..endStringSliceIndex)
|
234
|
+
if varName.include? ":"
|
235
|
+
varName = varName.slice(0..varName.index(":")-1)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
return varName.strip
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class AbstractClassAnalyzer
|
4
|
+
def initialize
|
5
|
+
@curlyBraces = 0
|
6
|
+
@funcCurlyBraces = 0
|
7
|
+
@functionName = nil
|
8
|
+
@funcLines = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def updateCurlyBraceIndex (line)
|
12
|
+
if line.include? "{"
|
13
|
+
@curlyBraces = @curlyBraces + 1
|
14
|
+
end
|
15
|
+
|
16
|
+
if line.include? "}"
|
17
|
+
@curlyBraces = @curlyBraces - 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def didReachEndOfClass
|
22
|
+
@curlyBraces == 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def resetClassStats
|
26
|
+
@curlyBraces = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def updateFunctionCurlyBraceIndex (line)
|
30
|
+
if line.include? "{"
|
31
|
+
@funcCurlyBraces = @funcCurlyBraces + 1
|
32
|
+
end
|
33
|
+
|
34
|
+
if line.include? "}"
|
35
|
+
@funcCurlyBraces = @funcCurlyBraces - 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def didReachEndOfFunction
|
40
|
+
@funcCurlyBraces == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def resetFunctionStats
|
44
|
+
@funcCurlyBraces = 0
|
45
|
+
@funcLines = 0
|
46
|
+
@functionName = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class AnalyzedClassGenerator < AbstractClassAnalyzer
|
51
|
+
|
52
|
+
def generateAnalyzedClassesForFile (file)
|
53
|
+
analyzedClasses = Array.new
|
54
|
+
analyzedClass = AnalyzedClass.new
|
55
|
+
|
56
|
+
f = File.open(file, "r")
|
57
|
+
f.each_line do |line|
|
58
|
+
tempClassName = classNameForLine line, analyzedClass.name
|
59
|
+
if tempClassName != nil
|
60
|
+
analyzedClass.name = tempClassName
|
61
|
+
end
|
62
|
+
|
63
|
+
if analyzedClass.name != nil
|
64
|
+
if line.strip.length > 1
|
65
|
+
analyzedClass.numberOfLines += 1
|
66
|
+
end
|
67
|
+
|
68
|
+
if analyzedClass.fileName == nil
|
69
|
+
analyzedClass.fileName = file
|
70
|
+
end
|
71
|
+
updateCurlyBraceIndex line
|
72
|
+
|
73
|
+
if line.include? "func "
|
74
|
+
@functionName = line.slice((line.index("func ") + 5)..(line.index("(")-1))
|
75
|
+
end
|
76
|
+
|
77
|
+
if @functionName != nil
|
78
|
+
updateFunctionCurlyBraceIndex line
|
79
|
+
|
80
|
+
if line.strip.length > 0
|
81
|
+
@funcLines = @funcLines + 1
|
82
|
+
end
|
83
|
+
|
84
|
+
if didReachEndOfFunction
|
85
|
+
analyzedClass.addFunction(@functionName, @funcLines)
|
86
|
+
resetFunctionStats
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
if (line.include? "var " or line.include? "let ")
|
91
|
+
variable = Variable.new.variableForLine line
|
92
|
+
analyzedClass.addVariable variable
|
93
|
+
end
|
94
|
+
|
95
|
+
if didReachEndOfClass
|
96
|
+
analyzedClasses.push(analyzedClass)
|
97
|
+
resetClassStats
|
98
|
+
analyzedClass = AnalyzedClass.new
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
f.close
|
103
|
+
|
104
|
+
return analyzedClasses
|
105
|
+
end
|
106
|
+
|
107
|
+
def classNameForLine (line, name)
|
108
|
+
if LineDeterminator.new(line).isClass and name == nil
|
109
|
+
if line.include? ":"
|
110
|
+
return line.strip.slice(5..(line.strip.index(":")-1))
|
111
|
+
else
|
112
|
+
strippedLine = line.gsub("class", "").strip
|
113
|
+
return strippedLine.slice(0..(strippedLine.index(" ")-1))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
class AnalyzedTestClassGenerator
|
122
|
+
|
123
|
+
def initialize (analyzedClasses, analyzedTestClasses, testCaseDirectory)
|
124
|
+
@analyzedClasses = analyzedClasses
|
125
|
+
@analyzedTestClasses = analyzedTestClasses
|
126
|
+
@testCaseDirectory = testCaseDirectory
|
127
|
+
end
|
128
|
+
|
129
|
+
def generateAnalyzedTestClasses
|
130
|
+
testedFunctionsMap = Hash.new
|
131
|
+
curlyBraces = 0
|
132
|
+
count = 0
|
133
|
+
funcCurlyBraces = 0
|
134
|
+
funcLines = 0
|
135
|
+
name = nil
|
136
|
+
testClass = nil
|
137
|
+
Dir.glob("#{@testCaseDirectory}/**/*.swift") do |item|
|
138
|
+
next if item == '.' or item == '..'
|
139
|
+
f = File.open(item, "r")
|
140
|
+
f.each_line do |line|
|
141
|
+
tempName = AnalyzedClassGenerator.new.classNameForLine line, name
|
142
|
+
if tempName != nil
|
143
|
+
name = tempName
|
144
|
+
end
|
145
|
+
|
146
|
+
if name != nil
|
147
|
+
if line.include? "{"
|
148
|
+
curlyBraces = curlyBraces + 1
|
149
|
+
end
|
150
|
+
|
151
|
+
if line.include? "}"
|
152
|
+
curlyBraces = curlyBraces - 1
|
153
|
+
end
|
154
|
+
|
155
|
+
if testClass == nil
|
156
|
+
testClass = analyzedTestClassWithName name
|
157
|
+
end
|
158
|
+
|
159
|
+
variable = variableForLine testClass, line
|
160
|
+
if variable
|
161
|
+
for analyzedClass in @analyzedClasses
|
162
|
+
|
163
|
+
if variable.type == analyzedClass.name
|
164
|
+
|
165
|
+
for function in analyzedClass.functions
|
166
|
+
|
167
|
+
if line.include? function.name
|
168
|
+
# instance function
|
169
|
+
analyzedClass.addTestedFunction function
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
elsif line.strip.length > 9
|
178
|
+
|
179
|
+
for analyzedClass in @analyzedClasses
|
180
|
+
|
181
|
+
if line.include? analyzedClass.name
|
182
|
+
|
183
|
+
for function in analyzedClass.functions
|
184
|
+
if line.include? function.name
|
185
|
+
# Class function
|
186
|
+
analyzedClass.addTestedFunction function
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
if curlyBraces == 0
|
197
|
+
testClass = nil
|
198
|
+
name = nil
|
199
|
+
curlyBraces = 0
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
f.close
|
204
|
+
end
|
205
|
+
return testedFunctionsMap
|
206
|
+
end
|
207
|
+
|
208
|
+
def analyzedTestClassWithName (name)
|
209
|
+
for testClass in @analyzedTestClasses
|
210
|
+
if testClass.name == name.strip
|
211
|
+
return testClass
|
212
|
+
end
|
213
|
+
end
|
214
|
+
return nil
|
215
|
+
end
|
216
|
+
|
217
|
+
def variableForLine (testClass, line)
|
218
|
+
for variable in testClass.variablesWithType
|
219
|
+
if line.include? variable.name
|
220
|
+
return variable
|
221
|
+
end
|
222
|
+
end
|
223
|
+
return nil
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'LineDeterminator'
|
4
|
+
require_relative 'AnalyzedClass'
|
5
|
+
require_relative 'AnalyzedClassGenerator'
|
6
|
+
require_relative 'FormGenerator'
|
7
|
+
|
8
|
+
class ClassAnalyzer
|
9
|
+
|
10
|
+
def initialize (searchDirectoryArg, testCaseDirectoryArg, outputDirectoryOpt)
|
11
|
+
@searchDirectoryArg = searchDirectoryArg
|
12
|
+
@testCaseDirectoryArg = testCaseDirectoryArg
|
13
|
+
@outputDirectoryOpt = outputDirectoryOpt
|
14
|
+
@analyzedClasses = Array.new
|
15
|
+
@analyzedTestClasses = Array.new
|
16
|
+
@testedFunctionsMap = Hash.new
|
17
|
+
@numProjectFiles = 0
|
18
|
+
@numTestFiles = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def analyze
|
22
|
+
createClassAnalysisFiles
|
23
|
+
processTestFiles
|
24
|
+
|
25
|
+
generator = AnalyzedTestClassGenerator.new(@analyzedClasses, @analyzedTestClasses, @testCaseDirectoryArg)
|
26
|
+
@testedFunctionsMap = generator.generateAnalyzedTestClasses
|
27
|
+
|
28
|
+
formGen = FormGenerator.new(@outputDirectoryOpt, @testedFunctionsMap, @analyzedClasses, @numProjectFiles, @numTestFiles)
|
29
|
+
formGen.generateForm
|
30
|
+
end
|
31
|
+
|
32
|
+
def processTestFiles
|
33
|
+
counter = 0
|
34
|
+
Dir.glob("#{@testCaseDirectoryArg}/**/*.swift") do |item|
|
35
|
+
next if item == '.' or item == '..'
|
36
|
+
counter += 1
|
37
|
+
|
38
|
+
analyzedClasses = AnalyzedClassGenerator.new.generateAnalyzedClassesForFile item
|
39
|
+
@analyzedTestClasses += analyzedClasses
|
40
|
+
|
41
|
+
if counter % 50 == 0
|
42
|
+
print "Test Swift Files processed: #{counter}\r"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
print "Test Swift files processed: #{counter}\r"
|
46
|
+
puts
|
47
|
+
|
48
|
+
@numTestFiles = counter
|
49
|
+
end
|
50
|
+
|
51
|
+
def createClassAnalysisFiles
|
52
|
+
counter = 0
|
53
|
+
Dir.glob("#{@searchDirectoryArg}/**/*.swift") do |item|
|
54
|
+
next if item == '.' or item == '..'
|
55
|
+
counter += 1
|
56
|
+
|
57
|
+
analyzedClasses = AnalyzedClassGenerator.new.generateAnalyzedClassesForFile item
|
58
|
+
@analyzedClasses += analyzedClasses
|
59
|
+
|
60
|
+
if counter % 50 == 0
|
61
|
+
print "Swift Files processed: #{counter}\r"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
print "Swift Files processed: #{counter}\r"
|
65
|
+
puts
|
66
|
+
|
67
|
+
@numProjectFiles = counter
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'IndexHTMLFile'
|
4
|
+
require_relative 'AnalysisHTMLFile'
|
5
|
+
|
6
|
+
class FormGenerator
|
7
|
+
|
8
|
+
def initialize (outputDirectoryOpt, testedFunctionsMap, analyzedClasses, numProjectFiles, numTestFiles)
|
9
|
+
@analyzedClasses = analyzedClasses
|
10
|
+
@testedFunctionsMap = testedFunctionsMap
|
11
|
+
@totalLines = 0
|
12
|
+
@numClasses = 0
|
13
|
+
@numFunc = 0
|
14
|
+
@numProjectFiles = numProjectFiles
|
15
|
+
@numTestFiles = numTestFiles
|
16
|
+
@analysisDirectory = "SwiftCodeCoverage"
|
17
|
+
if outputDirectoryOpt != nil
|
18
|
+
if outputDirectoryOpt[-1,1] == "/"
|
19
|
+
outputDirectoryOpt = outputDirectoryOpt[0..-2]
|
20
|
+
end
|
21
|
+
puts outputDirectoryOpt
|
22
|
+
@analysisDirectory = "#{outputDirectoryOpt}/#{@analysisDirectory}"
|
23
|
+
end
|
24
|
+
|
25
|
+
@filesDir = "AnalysisFiles"
|
26
|
+
end
|
27
|
+
|
28
|
+
def generateForm
|
29
|
+
createProjectStats
|
30
|
+
printResultsToCommandLine
|
31
|
+
|
32
|
+
# Start creating HTML
|
33
|
+
|
34
|
+
puts
|
35
|
+
puts "Generating form..."
|
36
|
+
puts "#{@analysisDirectory}"
|
37
|
+
|
38
|
+
if File.directory?(@analysisDirectory)
|
39
|
+
FileUtils.rm_rf(@analysisDirectory)
|
40
|
+
end
|
41
|
+
Dir.mkdir(@analysisDirectory)
|
42
|
+
|
43
|
+
indexHTML = IndexHTMLFile.new(self)
|
44
|
+
indexHTML.beginWriting
|
45
|
+
|
46
|
+
for analyzedClass in @analyzedClasses
|
47
|
+
analysisFile = AnalysisHTMLFile.new("#{@analysisDirectory}/#{@filesDir}", analyzedClass)
|
48
|
+
analysisFile.writeFile
|
49
|
+
indexHTML.addAnalysisItem analyzedClass, analysisFile
|
50
|
+
end
|
51
|
+
|
52
|
+
indexHTML.endWriting
|
53
|
+
|
54
|
+
puts "Finished generating form at #{@analysisDirectory}"
|
55
|
+
|
56
|
+
# Finish HTML
|
57
|
+
end
|
58
|
+
|
59
|
+
def createProjectStats
|
60
|
+
for analyzedClass in @analyzedClasses
|
61
|
+
@numClasses += 1
|
62
|
+
@numFunc += analyzedClass.functions.count
|
63
|
+
@totalLines += analyzedClass.numberOfLines
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def functionsTested
|
68
|
+
numLines = 0
|
69
|
+
numFunctions = 0
|
70
|
+
for analyzedClass in @analyzedClasses
|
71
|
+
for function in analyzedClass.testedFunctions
|
72
|
+
numLines += function.numLines
|
73
|
+
numFunctions += 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
return numLines, numFunctions
|
77
|
+
end
|
78
|
+
|
79
|
+
def classesTested
|
80
|
+
numClasses = 0
|
81
|
+
for analyzedClass in @analyzedClasses
|
82
|
+
if analyzedClass.testedFunctions.count > 0
|
83
|
+
numClasses += 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return numClasses
|
87
|
+
end
|
88
|
+
|
89
|
+
def printResultsToCommandLine
|
90
|
+
|
91
|
+
puts
|
92
|
+
|
93
|
+
puts "Total classes: #{@numClasses}"
|
94
|
+
puts "Total functions: #{@numFunc}"
|
95
|
+
puts "Total lines: #{@totalLines}"
|
96
|
+
|
97
|
+
puts
|
98
|
+
|
99
|
+
numLinesTested, numFunctionsTested = functionsTested
|
100
|
+
|
101
|
+
puts "Total functions Tested: #{numFunctionsTested}"
|
102
|
+
puts "Total lines Tested: #{numLinesTested}"
|
103
|
+
|
104
|
+
percFunc = (numFunctionsTested / Float(@numFunc) * 100).round
|
105
|
+
percLines = (numLinesTested / Float(@totalLines) * 100).round
|
106
|
+
|
107
|
+
puts "Function coverage: #{percFunc}%"
|
108
|
+
puts "Line coverage: #{percLines}%"
|
109
|
+
end
|
110
|
+
|
111
|
+
def analyzedClasses
|
112
|
+
@analyzedClasses
|
113
|
+
end
|
114
|
+
|
115
|
+
def testedFunctionsMap
|
116
|
+
@testedFunctionsMap
|
117
|
+
end
|
118
|
+
|
119
|
+
def totalLines
|
120
|
+
@totalLines
|
121
|
+
end
|
122
|
+
|
123
|
+
def numClasses
|
124
|
+
@numClasses
|
125
|
+
end
|
126
|
+
|
127
|
+
def numFunc
|
128
|
+
@numFunc
|
129
|
+
end
|
130
|
+
|
131
|
+
def analysisDirectory
|
132
|
+
@analysisDirectory
|
133
|
+
end
|
134
|
+
|
135
|
+
def numProjectFiles
|
136
|
+
@numProjectFiles
|
137
|
+
end
|
138
|
+
|
139
|
+
def numTestFiles
|
140
|
+
@numTestFiles
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative 'FormGenerator'
|
4
|
+
require_relative 'AnalyzedClass'
|
5
|
+
|
6
|
+
class IndexHTMLFile
|
7
|
+
|
8
|
+
def initialize(formGenerator)
|
9
|
+
@formGenerator = formGenerator
|
10
|
+
@indexHTMLString = ""
|
11
|
+
end
|
12
|
+
|
13
|
+
def beginWriting
|
14
|
+
@indexHTML = File.new("#{@formGenerator.analysisDirectory}/index.html", "w+")
|
15
|
+
end
|
16
|
+
|
17
|
+
def addAnalysisItem (analyzedClass, analysisFile)
|
18
|
+
htmlFileName = analysisFile.name
|
19
|
+
htmlFileName = htmlFileName.gsub(".swift", "")
|
20
|
+
htmlFileName = htmlFileName.gsub("./", "")
|
21
|
+
|
22
|
+
@indexHTMLString += "<tr>"
|
23
|
+
|
24
|
+
@indexHTMLString += "\n<td>"
|
25
|
+
@indexHTMLString += "\n<a href=\"#{analysisFile.directory.gsub(@formGenerator.analysisDirectory + "/", "")}/#{analysisFile.name}.html\">#{htmlFileName}.swift</a>"
|
26
|
+
@indexHTMLString += "\n</td>"
|
27
|
+
|
28
|
+
numFunctions, numFunctionsTested, percFunctions = funcStats analyzedClass
|
29
|
+
color = colorForValidLinePercentage percFunctions
|
30
|
+
|
31
|
+
@indexHTMLString += "\n<td align=\"left\" bgcolor=\"#{color}\">"
|
32
|
+
@indexHTMLString += "\n#{percFunctions}% (#{numFunctionsTested}/#{numFunctions})"
|
33
|
+
@indexHTMLString += "\n</td>"
|
34
|
+
|
35
|
+
numLinesTested = analyzedClass.numberOfLinesTested
|
36
|
+
numLines = analyzedClass.numberOfLines
|
37
|
+
percLines = ((Float(numLinesTested) / Float(numLines)) * 100).round
|
38
|
+
color = colorForValidLinePercentage percLines
|
39
|
+
|
40
|
+
@indexHTMLString += "\n<td align=\"left\" bgcolor=\"#{color}\">"
|
41
|
+
@indexHTMLString += "\n#{percLines}% (#{numLinesTested}/#{numLines})"
|
42
|
+
@indexHTMLString += "\n</td>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def funcStats (analyzedClass)
|
46
|
+
|
47
|
+
numFunctionsTested = analyzedClass.testedFunctions.count
|
48
|
+
numFunctions = analyzedClass.functions.count
|
49
|
+
|
50
|
+
if numFunctionsTested == 0 or numFunctions == 0
|
51
|
+
return 0, 0, 0
|
52
|
+
end
|
53
|
+
|
54
|
+
percFunctions = ((Float(numFunctionsTested) / Float(numFunctions)) * 100).round
|
55
|
+
return numFunctions, numFunctionsTested, percFunctions
|
56
|
+
end
|
57
|
+
|
58
|
+
def addCoverageTable
|
59
|
+
@indexHTML.puts "<h4>OVERALL COVERAGE</h4>"
|
60
|
+
@indexHTML.puts "<table cellpadding=\"0\" cellspacing=\"10\" bgcolor=\"#E8E8E8\" width=\"100%\">"
|
61
|
+
@indexHTML.puts "<tr>"
|
62
|
+
@indexHTML.puts "<th>class</th>"
|
63
|
+
@indexHTML.puts "<th>function</th>"
|
64
|
+
@indexHTML.puts "<th>lines</th>"
|
65
|
+
@indexHTML.puts "</tr>"
|
66
|
+
|
67
|
+
@indexHTML.puts "<tr>"
|
68
|
+
|
69
|
+
percClassesTested = ((Float(@formGenerator.classesTested) / Float(@formGenerator.numClasses)) * 100).round
|
70
|
+
color = colorForValidLinePercentage percClassesTested
|
71
|
+
|
72
|
+
@indexHTML.puts "<td align=\"center\">"
|
73
|
+
@indexHTML.puts "<font color=\"#{color}\">#{percClassesTested}% (#{@formGenerator.classesTested}/#{@formGenerator.numClasses})</font>"
|
74
|
+
@indexHTML.puts "</td>"
|
75
|
+
|
76
|
+
numLinesTested, numFunctionsTested = @formGenerator.functionsTested
|
77
|
+
percFunctionsTested = ((Float(numFunctionsTested) / Float(@formGenerator.numFunc)) * 100).round
|
78
|
+
color = colorForValidLinePercentage percFunctionsTested
|
79
|
+
|
80
|
+
@indexHTML.puts "<td align=\"center\">"
|
81
|
+
@indexHTML.puts "<font color=\"#{color}\">#{percFunctionsTested}% (#{numFunctionsTested}/#{@formGenerator.numFunc})</font>"
|
82
|
+
@indexHTML.puts "</td>"
|
83
|
+
|
84
|
+
percLinesTested = ((Float(numLinesTested) / Float(@formGenerator.totalLines)) * 100).round
|
85
|
+
color = colorForValidLinePercentage percLinesTested
|
86
|
+
|
87
|
+
@indexHTML.puts "<td align=\"center\">"
|
88
|
+
@indexHTML.puts "<font color=\"#{color}\">#{percLinesTested}% (#{numLinesTested}/#{@formGenerator.totalLines})</font>"
|
89
|
+
@indexHTML.puts "</td>"
|
90
|
+
|
91
|
+
@indexHTML.puts "</tr>"
|
92
|
+
|
93
|
+
@indexHTML.puts "</table>"
|
94
|
+
end
|
95
|
+
|
96
|
+
def addTotalStatsTable
|
97
|
+
@indexHTML.puts "<h4>OVERALL STATS</h4>"
|
98
|
+
@indexHTML.puts "<table cellpadding=\"0\" cellspacing=\"10\" width=\"200\">"
|
99
|
+
|
100
|
+
@indexHTML.puts "<tr>"
|
101
|
+
@indexHTML.puts "<td align=\"left\">"
|
102
|
+
@indexHTML.puts "Total files:"
|
103
|
+
@indexHTML.puts "</td>"
|
104
|
+
@indexHTML.puts "<td align=\"left\">"
|
105
|
+
@indexHTML.puts "#{@formGenerator.numProjectFiles}"
|
106
|
+
@indexHTML.puts "</td>"
|
107
|
+
@indexHTML.puts "</tr>"
|
108
|
+
|
109
|
+
@indexHTML.puts "<tr>"
|
110
|
+
@indexHTML.puts "<td align=\"left\">"
|
111
|
+
@indexHTML.puts "Total test files:"
|
112
|
+
@indexHTML.puts "</td>"
|
113
|
+
@indexHTML.puts "<td align=\"left\">"
|
114
|
+
@indexHTML.puts "#{@formGenerator.numTestFiles}"
|
115
|
+
@indexHTML.puts "</td>"
|
116
|
+
@indexHTML.puts "</tr>"
|
117
|
+
|
118
|
+
@indexHTML.puts "<tr>"
|
119
|
+
@indexHTML.puts "<td align=\"left\">"
|
120
|
+
@indexHTML.puts "Total classes:"
|
121
|
+
@indexHTML.puts "</td>"
|
122
|
+
@indexHTML.puts "<td align=\"left\">"
|
123
|
+
@indexHTML.puts "#{@formGenerator.numClasses}"
|
124
|
+
@indexHTML.puts "</td>"
|
125
|
+
@indexHTML.puts "</tr>"
|
126
|
+
|
127
|
+
@indexHTML.puts "<tr>"
|
128
|
+
@indexHTML.puts "<td align=\"left\">"
|
129
|
+
@indexHTML.puts "Total functions:"
|
130
|
+
@indexHTML.puts "</td>"
|
131
|
+
@indexHTML.puts "<td align=\"left\">"
|
132
|
+
@indexHTML.puts "#{@formGenerator.numFunc}"
|
133
|
+
@indexHTML.puts "</td>"
|
134
|
+
@indexHTML.puts "</tr>"
|
135
|
+
|
136
|
+
@indexHTML.puts "</table>"
|
137
|
+
end
|
138
|
+
|
139
|
+
def addAnalysisFilesTable
|
140
|
+
@indexHTML.puts "<h4>COVERAGE BY FILES</h4>"
|
141
|
+
@indexHTML.puts "<table cellpadding=\"0\" cellspacing=\"10\" col width=\"600\">"
|
142
|
+
@indexHTML.puts "<tr>"
|
143
|
+
@indexHTML.puts "<th>File</th>"
|
144
|
+
@indexHTML.puts "<th>Functions</th>"
|
145
|
+
@indexHTML.puts "<th>Lines</th>"
|
146
|
+
@indexHTML.puts "</tr>"
|
147
|
+
@indexHTML.puts @indexHTMLString
|
148
|
+
@indexHTML.puts "</table>"
|
149
|
+
end
|
150
|
+
|
151
|
+
def colorForValidLinePercentage (percentage)
|
152
|
+
if percentage >= 90
|
153
|
+
return "#52CC52" # Green
|
154
|
+
end
|
155
|
+
|
156
|
+
if percentage >= 65 and percentage < 90
|
157
|
+
return "yellow"
|
158
|
+
end
|
159
|
+
|
160
|
+
if percentage < 65
|
161
|
+
return "#FF4D4D" # Red
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def endWriting
|
166
|
+
@indexHTML.puts "<HTML>"
|
167
|
+
@indexHTML.puts "<HEAD>"
|
168
|
+
@indexHTML.puts "<style> table { border: 1px solid; } </style>"
|
169
|
+
@indexHTML.puts "</HEAD>"
|
170
|
+
@indexHTML.puts "<BODY>"
|
171
|
+
addCoverageTable
|
172
|
+
addTotalStatsTable
|
173
|
+
addAnalysisFilesTable
|
174
|
+
@indexHTML.puts "</BODY></HTML>"
|
175
|
+
@indexHTML.close()
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class LineDeterminator
|
4
|
+
def initialize (line)
|
5
|
+
@strippedLine = line.strip
|
6
|
+
end
|
7
|
+
|
8
|
+
def isComment
|
9
|
+
@strippedLine[0...2] == "//" or @strippedLine[0...3] == "///"
|
10
|
+
end
|
11
|
+
|
12
|
+
def isVar
|
13
|
+
@strippedLine[0...3] == "var"
|
14
|
+
end
|
15
|
+
|
16
|
+
def isLet
|
17
|
+
@strippedLine[0...3] == "let"
|
18
|
+
end
|
19
|
+
|
20
|
+
def isClass
|
21
|
+
@strippedLine[0...5] == "class" and !(@strippedLine.include? "func")
|
22
|
+
end
|
23
|
+
|
24
|
+
def isFunction
|
25
|
+
@strippedLine[0...4] == "func"
|
26
|
+
end
|
27
|
+
|
28
|
+
def lineType
|
29
|
+
if isComment
|
30
|
+
return CommentLineType.new(@strippedLine)
|
31
|
+
end
|
32
|
+
|
33
|
+
if isVar
|
34
|
+
return VariableLineType.new(@strippedLine)
|
35
|
+
end
|
36
|
+
|
37
|
+
if isLet
|
38
|
+
return ConstantLineType.new(@strippedLine)
|
39
|
+
end
|
40
|
+
|
41
|
+
if isClass
|
42
|
+
return ClassLineType.new(@strippedLine)
|
43
|
+
end
|
44
|
+
|
45
|
+
return LineType.new(@strippedLine)
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dftcc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Morris
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Generates analysis report of code coverage
|
42
|
+
email:
|
43
|
+
- majorent@icloud.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- CODE_OF_CONDUCT.md
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- bin/console
|
55
|
+
- bin/dftcc
|
56
|
+
- bin/setup
|
57
|
+
- dftcc.gemspec
|
58
|
+
- lib/AnalysisHTMLFile.rb
|
59
|
+
- lib/AnalyzedClass.rb
|
60
|
+
- lib/AnalyzedClassGenerator.rb
|
61
|
+
- lib/ClassAnalyzer.rb
|
62
|
+
- lib/FormGenerator.rb
|
63
|
+
- lib/IndexHTMLFile.rb
|
64
|
+
- lib/LineDeterminator.rb
|
65
|
+
- lib/dftcc/version.rb
|
66
|
+
homepage: http://rubygems.org
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.0.14
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Generates analysis report of code coverage
|
90
|
+
test_files: []
|