From 7ff8806544381a0a350b4c852fd5daa11519bbef Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Sat, 20 Feb 2010 22:31:33 -0600 Subject: [PATCH] Refactored Issues/Projects in to abstract classes with further implementations. ALl tests passing. Ran into some frustrationg aspects of Groovy --- libpit/build.xml | 2 +- libpit/project.properties | 4 +- libpit/src/com/jdbernard/pit/FileIssue.groovy | 68 +++++++++++++++ .../src/com/jdbernard/pit/FileProject.groovy | 68 +++++++++++++++ libpit/src/com/jdbernard/pit/Issue.groovy | 50 ++--------- libpit/src/com/jdbernard/pit/Project.groovy | 77 +--------------- .../com/jdbernard/pit/CategoryTest.groovy | 16 ++-- ...{IssueTest.groovy => FileIssueTest.groovy} | 24 ++--- ...jectTest.groovy => FileProjectTest.groovy} | 32 ++----- .../test/com/jdbernard/pit/FilterTest.groovy | 87 ++++++++++++++++++- .../test/com/jdbernard/pit/MockProject.groovy | 10 +++ 11 files changed, 272 insertions(+), 166 deletions(-) create mode 100644 libpit/src/com/jdbernard/pit/FileIssue.groovy create mode 100644 libpit/src/com/jdbernard/pit/FileProject.groovy rename libpit/test/com/jdbernard/pit/{IssueTest.groovy => FileIssueTest.groovy} (79%) rename libpit/test/com/jdbernard/pit/{ProjectTest.groovy => FileProjectTest.groovy} (85%) create mode 100644 libpit/test/com/jdbernard/pit/MockProject.groovy diff --git a/libpit/build.xml b/libpit/build.xml index c40f8a2..e800404 100644 --- a/libpit/build.xml +++ b/libpit/build.xml @@ -88,7 +88,7 @@ - + diff --git a/libpit/project.properties b/libpit/project.properties index 154977a..4be3177 100644 --- a/libpit/project.properties +++ b/libpit/project.properties @@ -1,9 +1,9 @@ -#Thu Feb 18 12:01:49 CST 2010 +#Sat Feb 20 22:25:08 CST 2010 build.dir=build src.dir=src lib.shared.dir=../shared-libs test.dir=test -build.number=4 +build.number=53 expected.application.version=1.1.2 lib.dir=lib release.dir=release diff --git a/libpit/src/com/jdbernard/pit/FileIssue.groovy b/libpit/src/com/jdbernard/pit/FileIssue.groovy new file mode 100644 index 0000000..4f90c47 --- /dev/null +++ b/libpit/src/com/jdbernard/pit/FileIssue.groovy @@ -0,0 +1,68 @@ +package com.jdbernard.pit + +import java.lang.IllegalArgumentException as IAE + +public class FileIssue extends Issue { + + File source + + FileIssue(File file) { + + /* I do not like this construction, but groovy automatically + * calls obj.setProperty(...) when you type obj.property = ... + * There is an exception for fields accessed withing the class + * that defines them, it does not catt eh setter/getter, but + * this exception does not extend to subclasses accessing member + * variables of their parent class. So instead of using Issue's + * default constructor and setting the id, category, and priority + * fields here, we have to let Issue's constructor initialize + * those values.*/ + + super((file.name =~ /(\d+)([bcft])(\d).*/)[0][1], + Category.toCategory((file.name =~ /(\d+)([bcft])(\d).*/)[0][2]), + (file.name =~ /(\d+)([bcft])(\d).*/)[0][3].toInteger()) + + //def matcher = file.name =~ /(\d{4})([bftc])(\d).*/ + /*if (!matcher) return null + + id = matcher[0][1] + category = Category.toCategory(matcher[0][2]) + priority = matcher[0][3].toInteger()*/ + + this.source = file + + file.withReader { title = it.readLine() } + text = file.text + } + + void setCategory(Category c) { + super.setCategory(c) + source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) + } + + void setPriority(int p) { + super.setPriority(p) + source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) + } + + String getFilename() { return makeFilename(id, category, priority) } + + static boolean isValidFilename(String name) { + return name ==~ /(\d+)([bcft])(\d).*/ + } + + static String makeFilename(String id, Category category, int priority) { + + // bounds check priority + priority = Math.min(9, Math.max(0, priority)) + + //check for valid values of cateogry and id + if (category == null) + throw new IAE("Category must be non-null.") + if (!(id ==~ /\d+/)) + throw new IAE( "'${id}' is not a legal value for id.") + + return id + category.symbol + priority + ".rst"; + } + +} diff --git a/libpit/src/com/jdbernard/pit/FileProject.groovy b/libpit/src/com/jdbernard/pit/FileProject.groovy new file mode 100644 index 0000000..6d6b183 --- /dev/null +++ b/libpit/src/com/jdbernard/pit/FileProject.groovy @@ -0,0 +1,68 @@ +package com.jdbernard.pit + +class FileProject extends Project { + + File source + + FileProject(File dir) { + super(dir.name) + + if (!dir.isDirectory()) + throw new IllegalArgumentException( + "${dir.name} is not a directory.") + + this.source = dir + + dir.eachFile { child -> + + // add sub projects + if (child.isDirectory()) { + if ( child.name ==~ /\d{4}/) return // just an issue folder + + // otherwise build and add to list + projects[(child.name)] = new FileProject(child) + } else if (child.isFile()) { + def issue + + // if exception, then not an issue + try { issue = new FileIssue(child) } catch (all) { return } + + issues[(issue.id)] = issue + } + } + } + + public void rename(String newName) { + this.name = newName + } + + public void setName(String name) { + super.setName(name) + source.renameTo(new File(source.canonicalFile.parentFile, name)) + } + + public FileIssue createNewIssue(Map options) { + if (!options) options = [:] + if (!options.category) options.category = Category.TASK + if (!options.priority) options.priority = 5 + if (!options.text) options.text = "Default issue title.\n" + + "====================\n" + String id + if (issues.size() == 0) id = '0000' + else { + id = (issues.values().max { it.id.toInteger() }).id + id = (id.toInteger() + 1).toString().padLeft(id.length(), '0') + } + + def issueFile = new File(source, FileIssue.makeFilename(id, options.category, options.priority)) + assert !issueFile.exists() + issueFile.createNewFile() + issueFile.write(options.text) + + return new FileIssue(issueFile) + } + + @Override + String toString() { return name } + +} diff --git a/libpit/src/com/jdbernard/pit/Issue.groovy b/libpit/src/com/jdbernard/pit/Issue.groovy index 9e002ea..0f2e2da 100644 --- a/libpit/src/com/jdbernard/pit/Issue.groovy +++ b/libpit/src/com/jdbernard/pit/Issue.groovy @@ -4,62 +4,26 @@ import java.lang.IllegalArgumentException as IAE public class Issue { - final String id + String id Category category int priority String title String text - File source - Issue(File file) { - - def matcher = file.name =~ /(\d{4})([bftc])(\d).*/ - if (!matcher) return null - - this.source = file - - id = matcher[0][1] - category = Category.toCategory(matcher[0][2]) - priority = matcher[0][3].toInteger() - - file.withReader { title = it.readLine() } - text = file.text + Issue(String id, Category c = Category.TASK, int p = 9) { + this.id = id + this.category = c + this.priority = p } - /** - */ void setCategory(Category c) { - - if (category == null) + if (c == null) throw new IAE("Category cannot be null.") this.category = c - source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) } - void setPriority(int p) { - - // bounds check priority - priority = Math.min(9, Math.max(0, priority)) - - source.renameTo(new File(source.canonicalFile.parentFile, getFilename())) - } - - String getFilename() { return makeFilename(id, category, priority) } - - static String makeFilename(String id, Category category, int priority) { - - // bounds check priority - priority = Math.min(9, Math.max(0, priority)) - - //check for valid values of cateogry and id - if (category == null) - throw new IAE("Category must be non-null.") - if (!(/\d+/ ==~ id)) - throw new IAE( "'${id}' is not a legal value for id.") - - return id + category.symbol + priority + ".rst"; - } + void setPriority(int p) { priority = Math.min(9, Math.max(0, p)) } @Override String toString() { return "${id}(${priority}): ${category} ${title}" } diff --git a/libpit/src/com/jdbernard/pit/Project.groovy b/libpit/src/com/jdbernard/pit/Project.groovy index 88d259b..ec0b637 100644 --- a/libpit/src/com/jdbernard/pit/Project.groovy +++ b/libpit/src/com/jdbernard/pit/Project.groovy @@ -1,46 +1,13 @@ package com.jdbernard.pit -class Project { +public abstract class Project { String name Map issues = [:] Map projects = [:] - File source - Project(File dir) { - if (!dir.isDirectory()) - throw new IllegalArgumentException( - "${dir.name} is not a directory.") + Project(String name) { this.name = name } - this.source = dir - this.name = dir.name - - dir.eachFile { child -> - - // add sub projects - if (child.isDirectory()) { - if ( child.name ==~ /\d{4}/) return // just an issue folder - - // otherwise build and add to list - projects[(child.name)] = new Project(child) - } else if (child.isFile()) { - def issue - - // if exception, then not an issue - try { issue = new Issue(child) } catch (all) { return } - - issues[(issue.id)] = issue - } - } - } - - public void rename(String newName) { - this.name = newName - source.renameTo(new File(source.canonicalFile.parentFile, newName)) - } - - public void setName(String name) { rename(name) } - public void eachIssue(Filter filter = null, Closure c) { def sorter = filter?.issueSorter ?: Filter.defaultIssueSorter for (i in issues.values().sort(sorter)) @@ -55,46 +22,8 @@ class Project { c.call(p) } - /*public void each(Filter filter = null, Closure c) { - def is = filter?.issueSorter ?: Filter.defaultIssueSorter - def ps = filter?.projectSorter ?: Filter.defaultProjectSorter - - for (issue in issues.values().sort(is)) { - if (filter && !filter.accept(issue)) - return - - c.call(issue) - } - - for (project in projects.values().sort(ps)) { - if (filter && !filter.accept(project)) - return - - c.call(project) - } - }*/ - - public Issue createNewIssue(Map options) { - if (!options.category) options.category = Category.TASK - if (!options.priority) options.priority = 5 - if (!options.text) options.text = "Default issue title.\n" + - "====================\n" - String id - if (issues.size() == 0) id = '0000' - else { - id = (issues.values().max { it.id.toInteger() }).id - id = (id.toInteger() + 1).toString().padLeft(id.length(), '0') - } - - def issueFile = new File(source, Issue.makeFilename(id, options.category, options.priority)) - assert !issueFile.exists() - issueFile.createNewFile() - issueFile.write(options.text) - - return new Issue(issueFile) - } - @Override String toString() { return name } + public abstract Issue createNewIssue(Map options) } diff --git a/libpit/test/com/jdbernard/pit/CategoryTest.groovy b/libpit/test/com/jdbernard/pit/CategoryTest.groovy index b312d74..5b473d1 100644 --- a/libpit/test/com/jdbernard/pit/CategoryTest.groovy +++ b/libpit/test/com/jdbernard/pit/CategoryTest.groovy @@ -1,4 +1,4 @@ -public package com.jdbernard.pit +package com.jdbernard.pit import org.junit.Test import static org.junit.Assert.assertEquals @@ -7,7 +7,7 @@ import static com.jdbernard.pit.Category.toCategory class CategoryTest { - @Test testToCategory() { + @Test void testToCategory() { assertEquals toCategory("BUG"), Category.BUG assertEquals toCategory("FEATURE"), Category.FEATURE @@ -16,21 +16,21 @@ class CategoryTest { assertEquals toCategory("bug"), Category.BUG assertEquals toCategory("feature"), Category.FEATURE - assertEquals toCategory("task"), Category.TASk + assertEquals toCategory("task"), Category.TASK assertEquals toCategory("closed"), Category.CLOSED assertEquals toCategory("b"), Category.BUG assertEquals toCategory("f"), Category.FEATURE - assertEquals toCategory("t"), Category.TASk + assertEquals toCategory("t"), Category.TASK assertEquals toCategory("c"), Category.CLOSED } - @Test testGetSymbol() { + @Test void testGetSymbol() { assertEquals Category.BUG.symbol, "b" - assertEquals Category.CLOSED.symbol "c" - assertEquals Category.FEATURE.symbol "f" - assertEquals Category.TASK.symbol "t" + assertEquals Category.CLOSED.symbol, "c" + assertEquals Category.FEATURE.symbol, "f" + assertEquals Category.TASK.symbol, "t" } } diff --git a/libpit/test/com/jdbernard/pit/IssueTest.groovy b/libpit/test/com/jdbernard/pit/FileIssueTest.groovy similarity index 79% rename from libpit/test/com/jdbernard/pit/IssueTest.groovy rename to libpit/test/com/jdbernard/pit/FileIssueTest.groovy index 456e968..b4daa99 100644 --- a/libpit/test/com/jdbernard/pit/IssueTest.groovy +++ b/libpit/test/com/jdbernard/pit/FileIssueTest.groovy @@ -5,7 +5,7 @@ import static org.junit.Assert.assertTrue import static org.junit.Assert.assertFalse import static org.junit.Assert.assertEquals -class IssueTest { +class FileIssueTest { def issues File testDir @@ -22,7 +22,7 @@ class IssueTest { "Add the killer feature to the killer app.\n" + "=========================================\n\n" + "Make our killer app shine!.") - issues << new Issue(issueFile) + issues << new FileIssue(issueFile) issueFile = new File(testDir, '0002t5.rst') issueFile.write( @@ -30,7 +30,7 @@ class IssueTest { "==============\n\n" + "The office is seriously lacking in sugary donuts.\n\n" + "We must rectify this at once!") - issues << new Issue(issueFile) + issues << new FileIssue(issueFile) } @After void deleteIssueFiles() { @@ -73,7 +73,7 @@ class IssueTest { @Test void testConstruction() { File issueFile = new File(testDir, '0001f1.rst') - Issue issue = new Issue(issueFile) + Issue issue = new FileIssue(issueFile) assertEquals issue.id , "0001" assertEquals issue.category , Category.FEATURE @@ -86,20 +86,20 @@ class IssueTest { } @Test void testMakeFilename() { - assertEquals Issue.makeFilename('0001', Category.BUG, 5) , '0001b5.rst' - assertEquals Issue.makeFilename('0010', Category.FEATURE, 1), '0010f1.rst' - assertEquals Issue.makeFilename('0002', Category.CLOSED, 3) , '0002c3.rst' - assertEquals Issue.makeFilename('0001', Category.BUG, -2) , '0001b0.rst' - assertEquals Issue.makeFilename('0001', Category.TASK, 10) , '0001t9.rst' - assertEquals Issue.makeFilename('00101', Category.BUG, 5) , '00101b5.rst' + assertEquals FileIssue.makeFilename('0001', Category.BUG, 5) , '0001b5.rst' + assertEquals FileIssue.makeFilename('0010', Category.FEATURE, 1), '0010f1.rst' + assertEquals FileIssue.makeFilename('0002', Category.CLOSED, 3) , '0002c3.rst' + assertEquals FileIssue.makeFilename('0001', Category.BUG, -2) , '0001b0.rst' + assertEquals FileIssue.makeFilename('0001', Category.TASK, 10) , '0001t9.rst' + assertEquals FileIssue.makeFilename('00101', Category.BUG, 5) , '00101b5.rst' try { - Issue.makeFilename('badid', Category.BUG, 5) + FileIssue.makeFilename('badid', Category.BUG, 5) assertTrue 'Issue.makeFilename() succeeded with bad id input.', false } catch (IllegalArgumentException iae) {} try { - Issue.makeFilename('0002', null, 5) + FileIssue.makeFilename('0002', null, 5) assertTrue 'Issue.makeFilename() succeeded given no Category.', false } catch (IllegalArgumentException iae) {} } diff --git a/libpit/test/com/jdbernard/pit/ProjectTest.groovy b/libpit/test/com/jdbernard/pit/FileProjectTest.groovy similarity index 85% rename from libpit/test/com/jdbernard/pit/ProjectTest.groovy rename to libpit/test/com/jdbernard/pit/FileProjectTest.groovy index f3627df..7f0ae1d 100644 --- a/libpit/test/com/jdbernard/pit/ProjectTest.groovy +++ b/libpit/test/com/jdbernard/pit/FileProjectTest.groovy @@ -8,7 +8,7 @@ import static org.junit.Assert.assertFalse import static org.junit.Assert.assertNotNull import static org.junit.Assert.assertTrue -class ProjectTest { +class FileProjectTest { File testDir Project rootProj @@ -69,7 +69,7 @@ class ProjectTest { subDir = new File(testDir, 'emptyproj') subDir.mkdirs() - rootProj = new Project(testDir) + rootProj = new FileProject(testDir) } @After void deleteTestProjects() { @@ -80,11 +80,11 @@ class ProjectTest { } @Test void testConstruction() { - Project proj = new Project(testDir) + Project proj = new FileProject(testDir) assertEquals proj.name, 'testdir' assertEquals proj.issues.size(), 3 - assertEquals proj.projects.size(), 1 + assertEquals proj.projects.size(), 2 // Issue construction in general is under test in IssueTest // just check that the issues actually exists @@ -110,13 +110,14 @@ class ProjectTest { 'Zippners are not zippning.' assertNotNull proj.projects.emptyproj - assertEquals proj.projects.emptyproj.size(), 0 + assertEquals proj.projects.emptyproj.issues.size(), 0 + assertEquals proj.projects.emptyproj.projects.size(), 0 } @Test void testRename() { assert rootProj.name == 'testdir' - rootProj.rename('renamedTestDir') + rootProj.name = 'renamedTestDir' assertEquals rootProj.name, 'renamedTestDir' assertTrue new File('renamedTestDir').exists() @@ -146,23 +147,4 @@ class ProjectTest { } - /*@Test void testEachIssue() { - def expectedList = [rootProj.issues['0001'], - rootProj.issues['0002'], rootProj.issues['0003']] - - // sort using default ordering (ids ascending) - def actualList = [] - rootProj.eachIssue { actualList << it } - - assertArrayEquals expectedList, actualList - - // sort using reverse ordering (ids descending) - expectedList = expectedList.reverse() - actualList = [] - - rootProj.eachIssue( - new Filter(issueSorter: { -(it.id.toInteger()) })) - { actualList << it } - }*/ - } diff --git a/libpit/test/com/jdbernard/pit/FilterTest.groovy b/libpit/test/com/jdbernard/pit/FilterTest.groovy index cf9c89e..b0cd2dd 100644 --- a/libpit/test/com/jdbernard/pit/FilterTest.groovy +++ b/libpit/test/com/jdbernard/pit/FilterTest.groovy @@ -1,11 +1,96 @@ package com.jdbernard.pit import org.junit.Test +import org.junit.Before +import org.junit.After + import static org.junit.Assert.assertTrue +import static org.junit.Assert.assertFalse class FilterTest { - @Test void emptyTest() { + Project proj + + @Before void setUpIssues() { + + proj = new MockProject('proj1') + + def issue = new Issue( '0000', Category.TASK, 5) + proj.issues['0000'] = issue + + issue = new Issue('0001', Category.BUG, 3) + proj.issues['0001'] = issue + + issue = new Issue('0002', Category.CLOSED, 9) + proj.issues['0002'] = issue + + issue = new Issue('0003', Category.FEATURE, 0) + proj.issues['0003'] = issue + + def subProj = new MockProject('subproj1') + proj.projects['subproj1'] = subProj + + subProj = new MockProject('subproj2') + proj.projects['subproj2'] = subProj + + } + + @Test void testDefaultFilter() { + Filter f = new Filter() + + proj.issues.values().each { assertTrue f.accept(it) } + proj.projects.values().each { assertTrue f.accept(it) } + } + + @Test void testPriorityIssueFilter() { + Filter f = new Filter(priority: 9) + + proj.eachIssue { assertTrue f.accept(it) } + + f.priority = 6 + assertTrue f.accept(proj.issues['0000']) + assertTrue f.accept(proj.issues['0001']) + assertFalse f.accept(proj.issues['0002']) + assertTrue f.accept(proj.issues['0003']) + + f.priority = 5 + assertTrue f.accept(proj.issues['0000']) + assertTrue f.accept(proj.issues['0001']) + assertFalse f.accept(proj.issues['0002']) + assertTrue f.accept(proj.issues['0003']) + + f.priority = 0 + assertFalse f.accept(proj.issues['0000']) + assertFalse f.accept(proj.issues['0001']) + assertFalse f.accept(proj.issues['0002']) + assertTrue f.accept(proj.issues['0003']) + + } + + @Test void testCategoryFilter() { + Filter f = new Filter(categories: + [Category.BUG, Category.FEATURE, Category.TASK]) + + assertTrue f.accept(proj.issues['0000']) + assertTrue f.accept(proj.issues['0001']) + assertFalse f.accept(proj.issues['0002']) + assertTrue f.accept(proj.issues['0003']) + + f.categories = [ Category.CLOSED ] + assertFalse f.accept(proj.issues['0000']) + assertFalse f.accept(proj.issues['0001']) + assertTrue f.accept(proj.issues['0002']) + assertFalse f.accept(proj.issues['0003']) + + f.categories = [ Category.BUG, Category.FEATURE ] + assertFalse f.accept(proj.issues['0000']) + assertTrue f.accept(proj.issues['0001']) + assertFalse f.accept(proj.issues['0002']) + assertTrue f.accept(proj.issues['0003']) + + } + + @Test void testProjectFilter() { } diff --git a/libpit/test/com/jdbernard/pit/MockProject.groovy b/libpit/test/com/jdbernard/pit/MockProject.groovy new file mode 100644 index 0000000..2eb569d --- /dev/null +++ b/libpit/test/com/jdbernard/pit/MockProject.groovy @@ -0,0 +1,10 @@ +package com.jdbernard.pit + +class MockProject extends Project { + + public MockProject(String name) { super(name) } + + public Issue createNewIssue(Map options) { + throw new UnsupportedOperationException() + } +}