SystemOrganization addCategory: #HudsonBuildTools! Object subclass: #HDReport instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'HudsonBuildTools'! HDReport subclass: #HDLintReport instanceVariableNames: 'environment rules' classVariableNames: '' poolDictionaries: '' category: 'HudsonBuildTools'! !HDLintReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:19'! runClasses: aCollectionOfClasses named: aString | classEnvironment | classEnvironment := BrowserEnvironment new forClasses: aCollectionOfClasses. classEnvironment label: aString. ^ self runEnvironment: classEnvironment! ! !HDLintReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:20'! runEnvironment: anEnvironment ^ self new initializeOn: anEnvironment; run! ! !HDLintReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:19'! runPackage: aString | packageEnvironment | packageEnvironment := BrowserEnvironment new forPackageNames: (Array with: aString). packageEnvironment label: aString. ^ self runEnvironment: packageEnvironment! ! !HDLintReport methodsFor: 'generating' stamp: 'lr 7/4/2010 22:36'! generateClass: aClass on: aStream | sourceStream sourceName | sourceStream := WriteStream on: String new. sourceName := environment name , '-' , aClass name , '.st'. aStream tab; nextPutAll: ''; nextPut: Character lf. self generateClass: aClass source: sourceStream on: aStream. self generateClass: aClass class source: sourceStream on: aStream. aStream tab; nextPutAll: ''; nextPut: Character lf. FileDirectory default forceNewFileNamed: sourceName do: [ :stream | stream nextPutAll: sourceStream contents ]! ! !HDLintReport methodsFor: 'generating' stamp: 'lr 7/4/2010 20:46'! generateClass: aClass selector: aSelector source: sourceStream on: aStream | offset source matching | offset := self lineAndColumn: sourceStream contents at: sourceStream position. sourceStream nextPutAll: (source := self convert: (aClass sourceCodeAt: aSelector)); nextPut: Character lf; nextPut: Character lf. matching := rules select: [ :each | (self isSelectorEnvironment: each result) and: [ each result includesSelector: aSelector in: aClass ] ]. self generateViolations: matching source: source offset: offset on: aStream! ! !HDLintReport methodsFor: 'generating' stamp: 'lr 7/4/2010 21:08'! generateClass: aClass source: sourceStream on: aStream | offset source matching selectors | offset := self lineAndColumn: sourceStream contents at: sourceStream position. sourceStream nextPutAll: (source := self convert: aClass definition); nextPut: Character lf; nextPut: Character lf. (environment definesClass: aClass) ifTrue: [ matching := rules select: [ :rule | (self isClassEnvironment: rule result) and: [ rule result includesClass: aClass ] ]. self generateViolations: matching source: source offset: offset on: aStream ]. (environment selectorsForClass: aClass) asSortedCollection do: [ :selector | self generateClass: aClass selector: selector source: sourceStream on: aStream ]! ! !HDLintReport methodsFor: 'generating' stamp: 'lr 7/4/2010 21:17'! generateOn: aStream aStream nextPutAll: ''; nextPut: Character lf. aStream nextPutAll: ''; nextPut: Character lf. (environment allClasses asSortedCollection: [ :a :b | a name <= b name ]) do: [ :class | self generateClass: class on: aStream ]. aStream nextPutAll: ''! ! !HDLintReport methodsFor: 'generating' stamp: 'lr 7/4/2010 22:35'! generateViolations: aCollection source: aString offset: aPoint on: aStream aCollection do: [ :rule | | interval start | interval := (rule result selectionIntervalFor: aString) ifNil: [ 1 to: aString size ]. start := self lineAndColumn: aString at: interval first. aStream tab; tab; nextPutAll: ''; nextPut: Character lf ]! ! !HDLintReport methodsFor: 'initialization' stamp: 'lr 7/4/2010 22:34'! initializeOn: anEnvironment environment := anEnvironment. rules := (RBCompositeLintRule rulesFor: RBBasicLintRule) reject: [ :each | each class name endsWith: 'SpellingRule' ]! ! !HDLintReport methodsFor: 'testing' stamp: 'lr 5/15/2010 14:05'! isClassEnvironment: anEnvironment ^ #(CategoryEnvironment ClassEnvironment VariableEnvironment) includes: anEnvironment class name! ! !HDLintReport methodsFor: 'testing' stamp: 'lr 5/15/2010 14:05'! isSelectorEnvironment: anEnvironment ^ #(SelectorEnvironment ParseTreeEnvironment VariableEnvironment) includes: anEnvironment class name! ! !HDLintReport methodsFor: 'private' stamp: 'lr 5/14/2010 22:29'! lineAndColumn: aString at: anInteger | line last stream | line := 1. last := 0. stream := aString readStream. [ (stream nextLine isNil or: [ anInteger <= stream position ]) ifTrue: [ ^ line @ (anInteger - last) ]. last := stream position. line := line + 1 ] repeat! ! !HDLintReport methodsFor: 'running' stamp: 'lr 7/4/2010 19:56'! run | stream | SmalllintChecker runRule: (RBCompositeLintRule rules: rules) onEnvironment: environment. stream := FileDirectory default forceNewFileNamed: environment name , '-Lint.xml'. [ self generateOn: stream ] ensure: [ stream close ]! ! !HDReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:17'! runCategories: aCollectionOfStrings ^ aCollectionOfStrings do: [ :each | self runCategory: each ]! ! !HDReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:17'! runCategory: aString ^ self runClasses: (Smalltalk organization classesInCategory: aString) named: aString! ! !HDReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:15'! runClasses: aCollectionOfClasses named: aString self subclassResponsibility! ! !HDReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:16'! runPackage: aString self subclassResponsibility! ! !HDReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:17'! runPackages: aCollectionOfStrings ^ aCollectionOfStrings do: [ :each | self runPackage: each ]! ! !HDReport methodsFor: 'private' stamp: 'lr 5/15/2010 14:27'! convert: aString ^ (aString asString copyReplaceAll: (String with: Character cr with: Character lf) with: (String with: Character lf)) copyReplaceAll: (String with: Character cr) with: (String with: Character lf)! ! !HDReport methodsFor: 'private' stamp: 'lr 5/14/2010 08:36'! encode: aString ^ ((aString asString copyReplaceAll: '&' with: '&') copyReplaceAll: '"' with: '"') copyReplaceAll: '<' with: '<'! ! HDReport subclass: #HDTestReport instanceVariableNames: 'suite stream suitePosition suiteTime suiteFailures suiteErrors' classVariableNames: '' poolDictionaries: '' category: 'HudsonBuildTools'! HDTestReport subclass: #HDCoverageReport instanceVariableNames: 'packages wrappers' classVariableNames: '' poolDictionaries: '' category: 'HudsonBuildTools'! !HDCoverageReport methodsFor: 'private' stamp: 'lr 6/9/2010 11:04'! addTestsIn: aTestAsserter to: aSet (aTestAsserter isKindOf: TestSuite) ifTrue: [ aTestAsserter tests do: [ :each | self addTestsIn: each to: aSet ] ]. (aTestAsserter isKindOf: TestCase) ifTrue: [ (aTestAsserter class respondsTo: #packageNamesUnderTest) ifTrue: [ aTestAsserter class packageNamesUnderTest do: [ :each | aSet add: (PackageInfo named: each) ] ] ]. ^ aSet! ! !HDCoverageReport methodsFor: 'generating' stamp: 'lr 6/9/2010 19:32'! generateCoverage stream := StandardFileStream forceNewFileNamed: suite name , '-Coverage.xml'. stream nextPutAll: ''; nextPut: Character lf. stream nextPutAll: ''; nextPut: Character lf. stream tab; nextPutAll: ''; nextPut: Character lf. stream tab; tab; nextPutAll: ''; nextPut: Character lf. packages do: [ :each | self generateCoveragePackage: each ]. stream tab; tab; nextPutAll: ''; nextPut: Character lf. stream tab; nextPutAll: ''; nextPut: Character lf. stream nextPutAll: ''; nextPut: Character lf. stream close! ! !HDCoverageReport methodsFor: 'generating' stamp: 'lr 6/9/2010 19:37'! generateCoveragePackage: aPackageInfo aPackageInfo classesAndMetaClasses do: [ :class | stream tab; tab; tab; nextPutAll: ''; nextPut: Character lf ]! ! !HDCoverageReport methodsFor: 'private' stamp: 'lr 6/9/2010 10:58'! ignoredSelectors ^ #(packageNamesUnderTest classNamesNotUnderTest)! ! !HDCoverageReport methodsFor: 'private' stamp: 'lr 6/9/2010 11:01'! methodsIn: aPackage aPackage isNil ifTrue: [ ^ #() ]. ^ aPackage methods reject: [ :method | (self ignoredSelectors includes: method methodSymbol) or: [ method compiledMethod isAbstract or: [ method compiledMethod refersToLiteral: #ignoreForCoverage ] ] ]! ! !HDCoverageReport methodsFor: 'private' stamp: 'lr 6/9/2010 10:51'! packagesIn: aTestAsserter ^ self addTestsIn: aTestAsserter to: Set new! ! !HDCoverageReport methodsFor: 'running' stamp: 'lr 6/9/2010 19:20'! run super run. self generateEmma! ! !HDCoverageReport methodsFor: 'running' stamp: 'lr 6/9/2010 19:30'! setUp super setUp. wrappers := ((packages := self packagesIn: suite) gather: [ :package | self methodsIn: package ]) collect: [ :each | HDTestCoverage on: each ]. wrappers do: [ :each | each install ]! ! !HDCoverageReport methodsFor: 'running' stamp: 'lr 6/9/2010 11:16'! tearDown wrappers do: [ :each | each uninstall ]. super tearDown! ! !HDTestReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:16'! runClasses: aCollectionOfClasses named: aString | suite classes | suite := TestSuite named: aString. classes := (aCollectionOfClasses select: [ :each | (each includesBehavior: TestCase) and: [ each isAbstract not ] ]) asSortedCollection: [ :a :b | a name <= b name ]. classes isEmpty ifTrue: [ ^ self ]. classes do: [ :each | each addToSuiteFromSelectors: suite ]. ^ self runSuite: suite! ! !HDTestReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:16'! runPackage: aString ^ self runClasses: (PackageInfo named: aString) classes named: aString! ! !HDTestReport class methodsFor: 'running' stamp: 'lr 5/14/2010 09:16'! runSuite: aTestSuite ^ self new initializeOn: aTestSuite; run! ! !HDTestReport methodsFor: 'private' stamp: 'lr 6/6/2010 18:44'! beginTestCase: aTestCase time: time stream tab; nextPutAll: ''; nextPut: Character lf! ! !HDTestReport methodsFor: 'private' stamp: 'lr 6/6/2010 18:45'! endTestCase stream tab; nextPutAll: ''; nextPut: Character lf! ! !HDTestReport methodsFor: 'initialization' stamp: 'lr 1/10/2010 10:22'! initializeOn: aTestSuite suite := aTestSuite. suitePosition := suiteTime := suiteFailures := suiteErrors := 0! ! !HDTestReport methodsFor: 'running' stamp: 'lr 6/9/2010 20:01'! run Author uniqueInstance ifUnknownAuthorUse: 'hudson' during: [ [ self setUp. suiteTime := [ self runAll ] timeToRun ] ensure: [ self tearDown ] ]! ! !HDTestReport methodsFor: 'running' stamp: 'pmm 6/6/2010 18:13'! run: aTestCase | error time stack | time := [ [ aTestCase runCase ] on: Error, TestFailure do: [ :err | error := err. stack := self stackTraceString: err of: aTestCase ] ] timeToRun. self beginTestCase: aTestCase time: time. (error isNil or: [ aTestCase expectedFailures includes: aTestCase selector ]) ifFalse: [ (error isKindOf: TestFailure) ifTrue: [ self writeError: error stack: stack ] ifFalse: [ self writeError: error stack: stack ] ]. self endTestCase! ! !HDTestReport methodsFor: 'running' stamp: 'lr 1/10/2010 01:27'! runAll suite tests do: [ :each | self run: each ]! ! !HDTestReport methodsFor: 'running' stamp: 'lr 5/15/2010 14:47'! setUp stream := StandardFileStream forceNewFileNamed: suite name , '-Test.xml'. stream nextPutAll: ''; nextPut: Character lf. stream nextPutAll: ''. "Now this is ugly. We want to update the time and the number of failures and errors, but still at the same time stream a valid XML. So remember this position and add some whitespace, that we can fill later." suitePosition := stream position - 1. stream nextPutAll: (String new: 100 withAll: $ ); nextPut: Character lf. "Initialize the test resources." suite resources do: [ :each | each isAvailable ifFalse: [ each signalInitializationError ] ]! ! !HDTestReport methodsFor: 'private' stamp: 'pmm 6/6/2010 18:13'! stackTraceString: err of: aTestCase ^ String streamContents: [ :str | | context | context := err signalerContext. [ context isNil or: [ context receiver == aTestCase and: [ context methodSelector == #runCase ] ] ] whileFalse: [ str print: context; nextPut: Character lf. context := context sender ] ] ! ! !HDTestReport methodsFor: 'running' stamp: 'lr 5/15/2010 14:47'! tearDown suite resources do: [ :each | each reset ]. stream tab; nextPutAll: ''; nextPut: Character lf. stream tab; nextPutAll: ''; nextPut: Character lf. stream nextPutAll: ''. stream position: suitePosition. stream nextPutAll: ' failures="'; print: suiteFailures; nextPutAll:'" errors="'; print: suiteErrors; nextPutAll: '" time="'; print: suiteTime / 1000.0; nextPutAll: '">'. stream close! ! !HDTestReport methodsFor: 'private' stamp: 'lr 6/9/2010 10:32'! writeError: error stack: stack suiteErrors := suiteErrors + 1. stream tab; tab; nextPutAll: ''; nextPutAll: (self encode: stack); nextPutAll: ''; nextPut: Character lf! ! !HDTestReport methodsFor: 'private' stamp: 'lr 6/9/2010 10:33'! writeFailure: error stack: stack suiteFailures := suiteFailures + 1. stream tab; tab; nextPutAll: ''; nextPutAll: (self encode: stack); nextPutAll: ''; nextPut: Character lf! ! ProtoObject subclass: #HDTestCoverage instanceVariableNames: 'counter reference method' classVariableNames: '' poolDictionaries: '' category: 'HudsonBuildTools'! !HDTestCoverage class methodsFor: 'instance creation' stamp: 'lr 6/9/2010 11:05'! on: aMethodReference ^ self new initializeOn: aMethodReference! ! !HDTestCoverage methodsFor: 'accessing' stamp: 'lr 6/9/2010 11:05'! counter ^ counter! ! !HDTestCoverage methodsFor: 'private' stamp: 'lr 6/9/2010 11:05'! doesNotUnderstand: aMessage ^ method perform: aMessage selector withArguments: aMessage arguments! ! !HDTestCoverage methodsFor: 'private' stamp: 'lr 6/9/2010 11:05'! flushCache! ! !HDTestCoverage methodsFor: 'testing' stamp: 'lr 6/9/2010 11:12'! hasRun ^ self counter > 0! ! !HDTestCoverage methodsFor: 'initialization' stamp: 'lr 6/9/2010 11:05'! initializeOn: aMethodReference counter := 0. reference := aMethodReference. method := reference compiledMethod! ! !HDTestCoverage methodsFor: 'actions' stamp: 'lr 6/9/2010 11:10'! install reference actualClass methodDictionary at: reference methodSymbol put: self. counter := 0! ! !HDTestCoverage methodsFor: 'private' stamp: 'lr 6/9/2010 11:06'! mark counter := counter + 1! ! !HDTestCoverage methodsFor: 'private' stamp: 'lr 6/9/2010 11:05'! reference ^ reference! ! !HDTestCoverage methodsFor: 'evaluation' stamp: 'lr 6/9/2010 11:06'! run: aSelector with: anArray in: aReceiver self mark. ^ aReceiver withArgs: anArray executeMethod: method! ! !HDTestCoverage methodsFor: 'actions' stamp: 'lr 6/9/2010 11:05'! uninstall reference actualClass methodDictionary at: reference methodSymbol put: method! !