diff --git a/.gitignore b/.gitignore
index f1e9957cfa..a4f6f3d915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -280,6 +280,22 @@ target
liuxin/.DS_Store
liuxin/src/.DS_Store
+students/1005475328/*
+students/1329920463/*
+students/1452302762/*
+students/14703250/*
+students/2842295913/*
+students/383117348/*
+students/404481481/*
+students/406400373/*
+students/549739951/*
+students/582161208/*
+students/592146505/*
+students/844620174/*
+students/87049319/*
+students/183549495/*
+
+
diff --git a/liuxin/knowledge-point/pom.xml b/liuxin/knowledge-point/pom.xml
new file mode 100644
index 0000000000..3dc438c7d9
--- /dev/null
+++ b/liuxin/knowledge-point/pom.xml
@@ -0,0 +1,32 @@
+
+ 4.0.0
+
+ com.coderising
+ knowledge-point
+ 0.0.1-SNAPSHOT
+ jar
+
+ knowledge-point
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+
+ junit
+ junit
+ 4.12
+
+
+
+
+
+ aliyunmaven
+ http://maven.aliyun.com/nexus/content/groups/public/
+
+
+
diff --git a/liuxin/knowledge-point/src/main/java/cas/CASSequence.java b/liuxin/knowledge-point/src/main/java/cas/CASSequence.java
new file mode 100644
index 0000000000..dcff77d9bf
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/cas/CASSequence.java
@@ -0,0 +1,18 @@
+package cas;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CASSequence{
+
+ private AtomicInteger count = new AtomicInteger(0);
+
+ public int next(){
+ while(true){
+ int current = count.get();
+ int next = current +1;
+ if(count.compareAndSet(current, next)){
+ return next;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/liuxin/knowledge-point/src/main/java/cas/NoBlockingStack.java b/liuxin/knowledge-point/src/main/java/cas/NoBlockingStack.java
new file mode 100644
index 0000000000..d7be44c69a
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/cas/NoBlockingStack.java
@@ -0,0 +1,34 @@
+package cas;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public class NoBlockingStack {
+ static class Node {
+ final E item;
+ Node next;
+ public Node(E item) { this.item = item; }
+ }
+
+ AtomicReference> head = new AtomicReference>();
+
+ public void push(E item) {
+ Node newHead = new Node(item);
+ Node oldHead;
+ do {
+ oldHead = head.get();
+ newHead.next = oldHead;
+ } while (!head.compareAndSet(oldHead, newHead));
+ }
+ public E pop() {
+ Node oldHead;
+ Node newHead;
+ do {
+ oldHead = head.get();
+ if (oldHead == null)
+ return null;
+ newHead = oldHead.next;
+ } while (!head.compareAndSet(oldHead,newHead));
+ return oldHead.item;
+ }
+
+}
diff --git a/liuxin/knowledge-point/src/main/java/cas/Sequence.java b/liuxin/knowledge-point/src/main/java/cas/Sequence.java
new file mode 100644
index 0000000000..688224e251
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/cas/Sequence.java
@@ -0,0 +1,11 @@
+package cas;
+
+public class Sequence{
+
+ private int value;
+
+ public int next(){
+ return value ++;
+ }
+
+}
diff --git a/liuxin/knowledge-point/src/main/java/threadlocal/Context.java b/liuxin/knowledge-point/src/main/java/threadlocal/Context.java
new file mode 100644
index 0000000000..d84584397b
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/threadlocal/Context.java
@@ -0,0 +1,20 @@
+package threadlocal;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Context {
+
+ private static final ThreadLocal txThreadLocal
+ = new ThreadLocal();
+
+ public static void setTransactionID(String txID) {
+ txThreadLocal.set(txID);
+
+ }
+
+ public static String getTransactionId() {
+ return txThreadLocal.get();
+ }
+
+}
+
diff --git a/liuxin/knowledge-point/src/main/java/threadlocal/TransactionManager.java b/liuxin/knowledge-point/src/main/java/threadlocal/TransactionManager.java
new file mode 100644
index 0000000000..8a5283fcab
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/threadlocal/TransactionManager.java
@@ -0,0 +1,22 @@
+package threadlocal;
+
+public class TransactionManager {
+ private static final ThreadLocal context = new ThreadLocal();
+
+ public static void startTransaction() {
+ // logic to start a transaction
+ // ...
+ String txID = null;
+ context.set(txID);
+ }
+
+ public static String getTransactionId() {
+ return context.get();
+ }
+
+ public static void endTransaction() {
+ // logic to end a transaction
+ // …
+ context.remove();
+ }
+}
diff --git a/liuxin/knowledge-point/src/main/java/threadpool/BlockingQueue.java b/liuxin/knowledge-point/src/main/java/threadpool/BlockingQueue.java
new file mode 100644
index 0000000000..faca2d2c70
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/threadpool/BlockingQueue.java
@@ -0,0 +1,35 @@
+package threadpool;
+import java.util.LinkedList;
+import java.util.List;
+
+public class BlockingQueue {
+
+ private List queue = new LinkedList();
+ private int limit = 10;
+
+ public BlockingQueue(int limit) {
+ this.limit = limit;
+ }
+
+ public synchronized void enqueue(Object item) throws InterruptedException {
+ while (this.queue.size() == this.limit) {
+ wait();
+ }
+ if (this.queue.size() == 0) {
+ notifyAll();
+ }
+ this.queue.add(item);
+ }
+
+ public synchronized Object dequeue() throws InterruptedException {
+ while (this.queue.size() == 0) {
+ wait();
+ }
+ if (this.queue.size() == this.limit) {
+ notifyAll();
+ }
+
+ return this.queue.remove(0);
+ }
+
+}
diff --git a/liuxin/knowledge-point/src/main/java/threadpool/Task.java b/liuxin/knowledge-point/src/main/java/threadpool/Task.java
new file mode 100644
index 0000000000..07413d9798
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/threadpool/Task.java
@@ -0,0 +1,5 @@
+package threadpool;
+
+public interface Task {
+ public void execute();
+}
diff --git a/liuxin/knowledge-point/src/main/java/threadpool/ThreadPool.java b/liuxin/knowledge-point/src/main/java/threadpool/ThreadPool.java
new file mode 100644
index 0000000000..f508f76eb5
--- /dev/null
+++ b/liuxin/knowledge-point/src/main/java/threadpool/ThreadPool.java
@@ -0,0 +1,37 @@
+package threadpool;
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ThreadPool {
+
+ private BlockingQueue taskQueue = null;
+ private List threads = new ArrayList();
+ private boolean isStopped = false;
+
+ public ThreadPool(int numOfThreads, int maxNumOfTasks){
+ taskQueue = new BlockingQueue(maxNumOfTasks);
+
+ for(int i=0; icom.coderising
ood-assignment0.0.1-SNAPSHOT
- jar
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.7
+ 1.7
+
+
+
+
+ jarood-assignmenthttp://maven.apache.org
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary1.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary1.java
new file mode 100644
index 0000000000..798cfbc7f9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary1.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.bridge;
+
+public class GraphicLibrary1 {
+ public void draw_a_line(int x1,int y1,int x2,int y2){
+
+ }
+ public void draw_a_circle(int x,int y, int r){
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary2.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary2.java
new file mode 100644
index 0000000000..2e67a1220b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/bridge/GraphicLibrary2.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.bridge;
+
+public class GraphicLibrary2 {
+ public void drawLine(int x1,int x2,int y1,int y2){
+
+ }
+ public void drawCircle(int x,int y, int r){
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilder.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilder.java
new file mode 100644
index 0000000000..daa431f139
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilder.java
@@ -0,0 +1,37 @@
+package com.coderising.dp.builder;
+
+public class TagBuilder {
+ private TagNode rootNode;
+ private TagNode currentNode;
+ private TagNode parentNode;
+ public TagBuilder(String rootTagName){
+ rootNode = new TagNode(rootTagName);
+ currentNode = rootNode;
+ parentNode = null;
+ }
+
+ public TagBuilder addChild(String childTagName){
+ parentNode = this.currentNode;
+ this.currentNode = new TagNode(childTagName);
+ parentNode.add(currentNode);
+ return this;
+ }
+ public TagBuilder addSibling(String siblingTagName){
+
+ this.currentNode = new TagNode(siblingTagName);
+ parentNode.add(this.currentNode);
+ return this;
+
+ }
+ public TagBuilder setAttribute(String name, String value){
+ this.currentNode.setAttribute(name, value);
+ return this;
+ }
+ public TagBuilder setText(String value){
+ this.currentNode.setValue(value);
+ return this;
+ }
+ public String toXML(){
+ return this.rootNode.toXML();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilderTest.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilderTest.java
new file mode 100644
index 0000000000..e30d20285b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagBuilderTest.java
@@ -0,0 +1,40 @@
+package com.coderising.dp.builder;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TagBuilderTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testToXML() {
+
+ TagBuilder builder = new TagBuilder("order");
+
+ String xml = builder.addChild("line-items")
+ .addChild("line-item").setAttribute("pid", "P3677").setAttribute("qty", "3")
+ .addSibling("line-item").setAttribute("pid", "P9877").setAttribute("qty", "10")
+ .toXML();
+
+ String expected = ""
+ + ""
+ + ""
+ + ""
+ + ""
+ + "";
+
+ System.out.println(xml);
+ assertEquals(expected, xml);
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagNode.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagNode.java
new file mode 100644
index 0000000000..2ac26ad7b9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/builder/TagNode.java
@@ -0,0 +1,83 @@
+package com.coderising.dp.builder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TagNode {
+ private String tagName;
+ private String tagValue;
+ private List children = new ArrayList<>();
+ private List attributes = new ArrayList<>();
+
+ public TagNode(String name){
+ this.tagName = name;
+ }
+ public void add(TagNode child){
+ this.children.add(child);
+ }
+ public void setAttribute(String name, String value) {
+ Attribute attr = findAttribute(name);
+ if(attr != null){
+ attr.value = value;
+ return;
+ }
+
+ attributes.add(new Attribute(name,value));
+ }
+ private Attribute findAttribute(String name){
+ for(Attribute attr : attributes){
+ if(attr.name.equals(name)){
+ return attr;
+ }
+ }
+ return null;
+ }
+ public void setValue(String value) {
+ this.tagValue = value;
+
+ }
+ public String getTagName() {
+ return tagName;
+ }
+ public List getChildren() {
+ return children;
+ }
+
+ private static class Attribute{
+ public Attribute(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+ String name;
+ String value;
+
+ }
+ public String toXML(){
+ return toXML(this);
+ }
+ private String toXML(TagNode node){
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("<").append(node.tagName);
+ if(node.attributes.size()> 0){
+ for(int i=0;i");
+ return buffer.toString();
+ }
+ buffer.append(">");
+ for(TagNode childNode : node.children){
+ buffer.append(toXML(childNode));
+ }
+ buffer.append("").append(node.tagName).append(">");
+
+
+ return buffer.toString();
+ }
+ private String toXML(Attribute attr){
+ return attr.name+"=\""+attr.value + "\"";
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Line.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Line.java
new file mode 100644
index 0000000000..b3c769e63a
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Line.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.composite;
+
+public class Line implements Shape {
+
+ @Override
+ public void draw() {
+
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Rectangle.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Rectangle.java
new file mode 100644
index 0000000000..2960351a35
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Rectangle.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.composite;
+
+public class Rectangle implements Shape {
+
+ @Override
+ public void draw() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Shape.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Shape.java
new file mode 100644
index 0000000000..4562f10b12
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Shape.java
@@ -0,0 +1,5 @@
+package com.coderising.dp.composite;
+
+public interface Shape {
+ public void draw();
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Square.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Square.java
new file mode 100644
index 0000000000..f106d65fd8
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Square.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.composite;
+
+public class Square implements Shape {
+
+ @Override
+ public void draw() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Text.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Text.java
new file mode 100644
index 0000000000..3543a08be3
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/composite/Text.java
@@ -0,0 +1,11 @@
+package com.coderising.dp.composite;
+
+public class Text implements Shape {
+
+ @Override
+ public void draw() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/Email.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/Email.java
new file mode 100644
index 0000000000..064de1e837
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/Email.java
@@ -0,0 +1,6 @@
+package com.coderising.dp.decorator;
+
+public interface Email {
+ public String getContent();
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailDecorator.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailDecorator.java
new file mode 100644
index 0000000000..d5379b0dd9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailDecorator.java
@@ -0,0 +1,5 @@
+package com.coderising.dp.decorator;
+
+public abstract class EmailDecorator implements Email{
+
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailImpl.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailImpl.java
new file mode 100644
index 0000000000..640aef6da3
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/dp/decorator/EmailImpl.java
@@ -0,0 +1,12 @@
+package com.coderising.dp.decorator;
+
+public class EmailImpl implements Email {
+ private String content;
+
+ public EmailImpl(String content) {
+ this.content = content;
+ }
+ public String getContent() {
+ return content;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/DateUtil.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/DateUtil.java
new file mode 100644
index 0000000000..0d0d01098f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/DateUtil.java
@@ -0,0 +1,10 @@
+package com.coderising.ood.ocp;
+
+public class DateUtil {
+
+ public static String getCurrentDateAsString() {
+
+ return null;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/Logger.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/Logger.java
new file mode 100644
index 0000000000..aca173e665
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/Logger.java
@@ -0,0 +1,38 @@
+package com.coderising.ood.ocp;
+
+public class Logger {
+
+ public final int RAW_LOG = 1;
+ public final int RAW_LOG_WITH_DATE = 2;
+ public final int EMAIL_LOG = 1;
+ public final int SMS_LOG = 2;
+ public final int PRINT_LOG = 3;
+
+ int type = 0;
+ int method = 0;
+
+ public Logger(int logType, int logMethod){
+ this.type = logType;
+ this.method = logMethod;
+ }
+ public void log(String msg){
+
+ String logMsg = msg;
+
+ if(this.type == RAW_LOG){
+ logMsg = msg;
+ } else if(this.type == RAW_LOG_WITH_DATE){
+ String txtDate = DateUtil.getCurrentDateAsString();
+ logMsg = txtDate + ": " + msg;
+ }
+
+ if(this.method == EMAIL_LOG){
+ MailUtil.send(logMsg);
+ } else if(this.method == SMS_LOG){
+ SMSUtil.send(logMsg);
+ } else if(this.method == PRINT_LOG){
+ System.out.println(logMsg);
+ }
+ }
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/MailUtil.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/MailUtil.java
new file mode 100644
index 0000000000..59d77649a2
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/MailUtil.java
@@ -0,0 +1,10 @@
+package com.coderising.ood.ocp;
+
+public class MailUtil {
+
+ public static void send(String logMsg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/SMSUtil.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/SMSUtil.java
new file mode 100644
index 0000000000..fab4cd01b7
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/SMSUtil.java
@@ -0,0 +1,10 @@
+package com.coderising.ood.ocp;
+
+public class SMSUtil {
+
+ public static void send(String logMsg) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Formatter.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Formatter.java
new file mode 100644
index 0000000000..b6e2ccbc16
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Formatter.java
@@ -0,0 +1,7 @@
+package com.coderising.ood.ocp.good;
+
+public interface Formatter {
+
+ String format(String msg);
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/FormatterFactory.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/FormatterFactory.java
new file mode 100644
index 0000000000..3c2009a674
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/FormatterFactory.java
@@ -0,0 +1,13 @@
+package com.coderising.ood.ocp.good;
+
+public class FormatterFactory {
+ public static Formatter createFormatter(int type){
+ if(type == 1){
+ return new RawFormatter();
+ }
+ if (type == 2){
+ return new HtmlFormatter();
+ }
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/HtmlFormatter.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/HtmlFormatter.java
new file mode 100644
index 0000000000..3d375f5acc
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/HtmlFormatter.java
@@ -0,0 +1,11 @@
+package com.coderising.ood.ocp.good;
+
+public class HtmlFormatter implements Formatter {
+
+ @Override
+ public String format(String msg) {
+
+ return null;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Logger.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Logger.java
new file mode 100644
index 0000000000..f206472d0d
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Logger.java
@@ -0,0 +1,18 @@
+package com.coderising.ood.ocp.good;
+
+public class Logger {
+
+ private Formatter formatter;
+ private Sender sender;
+
+ public Logger(Formatter formatter,Sender sender){
+ this.formatter = formatter;
+ this.sender = sender;
+ }
+ public void log(String msg){
+ sender.send(formatter.format(msg)) ;
+ }
+
+
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/RawFormatter.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/RawFormatter.java
new file mode 100644
index 0000000000..7f1cb4ae30
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/RawFormatter.java
@@ -0,0 +1,11 @@
+package com.coderising.ood.ocp.good;
+
+public class RawFormatter implements Formatter {
+
+ @Override
+ public String format(String msg) {
+
+ return null;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Sender.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Sender.java
new file mode 100644
index 0000000000..aaa46c1fb7
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/ocp/good/Sender.java
@@ -0,0 +1,7 @@
+package com.coderising.ood.ocp.good;
+
+public interface Sender {
+
+ void send(String msg);
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/MailBodyTemplate.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/MailBodyTemplate.java
new file mode 100644
index 0000000000..e5df642be9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/MailBodyTemplate.java
@@ -0,0 +1,5 @@
+package com.coderising.ood.srp.good.template;
+
+public interface MailBodyTemplate {
+ public String render();
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/TextMailBodyTemplate.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/TextMailBodyTemplate.java
new file mode 100644
index 0000000000..38793717a8
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good/template/TextMailBodyTemplate.java
@@ -0,0 +1,19 @@
+package com.coderising.ood.srp.good.template;
+
+import java.util.Map;
+
+public class TextMailBodyTemplate implements MailBodyTemplate {
+
+ private MapparamMap ;
+
+ public TextMailBodyTemplate(Map map){
+ paramMap = map;
+ }
+
+ @Override
+ public String render() {
+ //使用某种模板技术实现Render
+ return null;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Configuration.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Configuration.java
new file mode 100644
index 0000000000..55f0fad677
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Configuration.java
@@ -0,0 +1,23 @@
+package com.coderising.ood.srp.good1;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Configuration {
+
+ static Map configurations = new HashMap<>();
+ static{
+ configurations.put(ConfigurationKeys.SMTP_SERVER, "smtp.163.com");
+ configurations.put(ConfigurationKeys.ALT_SMTP_SERVER, "smtp1.163.com");
+ configurations.put(ConfigurationKeys.EMAIL_ADMIN, "admin@company.com");
+ }
+ /**
+ * 应该从配置文件读, 但是这里简化为直接从一个map 中去读
+ * @param key
+ * @return
+ */
+ public String getProperty(String key) {
+
+ return configurations.get(key);
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ConfigurationKeys.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ConfigurationKeys.java
new file mode 100644
index 0000000000..945db9004a
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ConfigurationKeys.java
@@ -0,0 +1,9 @@
+package com.coderising.ood.srp.good1;
+
+public class ConfigurationKeys {
+
+ public static final String SMTP_SERVER = "smtp.server";
+ public static final String ALT_SMTP_SERVER = "alt.smtp.server";
+ public static final String EMAIL_ADMIN = "email.admin";
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Mail.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Mail.java
new file mode 100644
index 0000000000..83099ed16a
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Mail.java
@@ -0,0 +1,29 @@
+package com.coderising.ood.srp.good1;
+
+import java.util.List;
+
+import com.coderising.ood.srp.good.template.MailBodyTemplate;
+
+public class Mail {
+
+ private User user;
+
+ public Mail(User u){
+ this.user = u;
+ }
+ public String getAddress(){
+ return user.getEMailAddress();
+ }
+ public String getSubject(){
+ return "您关注的产品降价了";
+ }
+ public String getBody(){
+
+ return "尊敬的 "+user.getName()+", 您关注的产品 " + this.buildProductDescList() + " 降价了,欢迎购买!" ;
+ }
+ private String buildProductDescList() {
+ List products = user.getSubscribedProducts();
+ //.... 实现略...
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/MailSender.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/MailSender.java
new file mode 100644
index 0000000000..ffd0543e22
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/MailSender.java
@@ -0,0 +1,36 @@
+package com.coderising.ood.srp.good1;
+
+
+public class MailSender {
+
+ private String fromAddress ;
+ private String smtpHost;
+ private String altSmtpHost;
+
+ public MailSender(Configuration config){
+ this.fromAddress = config.getProperty(ConfigurationKeys.EMAIL_ADMIN);
+ this.smtpHost = config.getProperty(ConfigurationKeys.SMTP_SERVER);
+ this.altSmtpHost = config.getProperty(ConfigurationKeys.ALT_SMTP_SERVER);
+ }
+
+ public void sendMail(Mail mail){
+ try{
+ sendEmail(mail,this.smtpHost);
+ }catch(Exception e){
+ try{
+ sendEmail(mail,this.altSmtpHost);
+ }catch (Exception ex){
+ System.out.println("通过备用 SMTP服务器发送邮件失败: " + ex.getMessage());
+ }
+
+ }
+ }
+
+ private void sendEmail(Mail mail, String smtpHost){
+
+ String toAddress = mail.getAddress();
+ String subject = mail.getSubject();
+ String msg = mail.getBody();
+ //发送邮件
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Product.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Product.java
new file mode 100644
index 0000000000..55617461cd
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/Product.java
@@ -0,0 +1,14 @@
+package com.coderising.ood.srp.good1;
+
+
+
+public class Product {
+
+ private String id;
+ private String desc;
+ public String getDescription(){
+ return desc;
+ }
+
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ProductService.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ProductService.java
new file mode 100644
index 0000000000..4109bfa9dc
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/ProductService.java
@@ -0,0 +1,9 @@
+package com.coderising.ood.srp.good1;
+
+
+public class ProductService {
+ public Product getPromotionProduct(){
+ //从文本文件中读取文件列表
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/PromotionJob.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/PromotionJob.java
new file mode 100644
index 0000000000..8e41069bd9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/PromotionJob.java
@@ -0,0 +1,24 @@
+package com.coderising.ood.srp.good1;
+
+import java.util.List;
+
+public class PromotionJob {
+
+ private ProductService productService = null ; //获取production service
+ private UserService userService = null ;// 获取UserService
+
+ public void run(){
+
+ Configuration cfg = new Configuration();
+
+ Product p = productService.getPromotionProduct();
+
+ List users = userService.getUsers(p);
+
+ MailSender mailSender = new MailSender(cfg);
+
+ for(User user : users){
+ mailSender.sendMail(new Mail(user));
+ }
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/User.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/User.java
new file mode 100644
index 0000000000..114476bb64
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/User.java
@@ -0,0 +1,24 @@
+package com.coderising.ood.srp.good1;
+
+import java.util.List;
+
+
+
+public class User {
+
+ private String name;
+ private String emailAddress;
+
+ private List subscribedProducts;
+
+ public String getName(){
+ return name;
+ }
+ public String getEMailAddress() {
+ return emailAddress;
+ }
+ public List getSubscribedProducts(){
+ return this.subscribedProducts;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/UserService.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/UserService.java
new file mode 100644
index 0000000000..1e08138cff
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good1/UserService.java
@@ -0,0 +1,11 @@
+package com.coderising.ood.srp.good1;
+
+import java.util.List;
+
+public class UserService {
+
+ public List getUsers(Product product){
+ //调用DAO相关的类从数据库中读取订阅产品的用户列表
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/ProductService.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/ProductService.java
new file mode 100644
index 0000000000..5ca5636291
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/ProductService.java
@@ -0,0 +1,12 @@
+package com.coderising.ood.srp.good2;
+
+import java.util.List;
+
+import com.coderising.ood.srp.good1.Product;
+
+public class ProductService {
+ public List getPromotionProducts(){
+ //从文本文件中读取文件列表
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/UserService.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/UserService.java
new file mode 100644
index 0000000000..f86307e701
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/good2/UserService.java
@@ -0,0 +1,13 @@
+package com.coderising.ood.srp.good2;
+
+import java.util.List;
+
+import com.coderising.ood.srp.good1.Product;
+import com.coderising.ood.srp.good1.User;
+
+public class UserService {
+ public List getUsers(List products){
+ //调用DAO相关的类从数据库中读取订阅产品的用户列表
+ return null;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/product_promotion.txt b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/product_promotion.txt
index 0c0124cc61..618f02b102 100644
--- a/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/product_promotion.txt
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/ood/srp/product_promotion.txt
@@ -1,3 +1,8 @@
+
+
+
+
+
P8756 iPhone8
P3946 XiaoMi10
P8904 Oppo_R15
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/PayrollService.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/PayrollService.java
new file mode 100644
index 0000000000..b0b4fec82f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/PayrollService.java
@@ -0,0 +1,49 @@
+package com.coderising.payroll;
+
+import java.util.List;
+
+import com.coderising.payroll.classification.CommissionedClassification;
+import com.coderising.payroll.classification.HourlyClassification;
+import com.coderising.payroll.classification.SalariedClassification;
+import com.coderising.payroll.domain.Employee;
+import com.coderising.payroll.domain.HoldMethod;
+import com.coderising.payroll.domain.Paycheck;
+import com.coderising.payroll.schedule.BiweeklySchedule;
+import com.coderising.payroll.schedule.MonthlySchedule;
+import com.coderising.payroll.schedule.WeeklySchedule;
+
+public class PayrollService {
+ public List getAllEmployees(){
+ return null;
+ }
+ public void savePaycheck(Paycheck pc){
+
+ }
+
+ public Employee addHourlyEmployee(String name, String address, double hourlyRate){
+ Employee e = new Employee(name, address);
+ e.setClassification(new HourlyClassification(hourlyRate));
+ e.setSchedule(new WeeklySchedule());
+ e.setPaymentMethod(new HoldMethod());
+ //保存员工到数据库.. 略
+ return e;
+ }
+
+ public Employee addSalariedEmployee(String name, String address, double salary){
+ Employee e = new Employee(name, address);
+ e.setClassification(new SalariedClassification(salary));
+ e.setSchedule(new MonthlySchedule());
+ e.setPaymentMethod(new HoldMethod());
+ //保存员工到数据库.. 略
+ return e;
+ }
+
+ public Employee addCommissionedEmployee(String name, String address, double salary, double saleRate){
+ Employee e = new Employee(name, address);
+ e.setClassification(new CommissionedClassification(salary, saleRate));
+ e.setSchedule(new BiweeklySchedule());
+ e.setPaymentMethod(new HoldMethod());
+ //保存员工到数据库.. 略
+ return e;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/NonAffiliation.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/NonAffiliation.java
new file mode 100644
index 0000000000..3cb6228aa4
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/NonAffiliation.java
@@ -0,0 +1,10 @@
+package com.coderising.payroll.affiliation;
+
+import com.coderising.payroll.domain.Affiliation;
+import com.coderising.payroll.domain.Paycheck;
+
+public class NonAffiliation implements Affiliation{
+ public double calculateDeductions(Paycheck pc){
+ return 0.0;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/UnionAffiliation.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/UnionAffiliation.java
new file mode 100644
index 0000000000..bbce4fa317
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/affiliation/UnionAffiliation.java
@@ -0,0 +1,14 @@
+package com.coderising.payroll.affiliation;
+
+import com.coderising.payroll.domain.Affiliation;
+import com.coderising.payroll.domain.Paycheck;
+
+public class UnionAffiliation implements Affiliation {
+
+ @Override
+ public double calculateDeductions(Paycheck pc) {
+
+ return 0;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/CommissionedClassification.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/CommissionedClassification.java
new file mode 100644
index 0000000000..f6a7ab4a63
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/CommissionedClassification.java
@@ -0,0 +1,31 @@
+package com.coderising.payroll.classification;
+
+import java.util.Date;
+import java.util.Map;
+
+import com.coderising.payroll.domain.Paycheck;
+import com.coderising.payroll.domain.PaymentClassification;
+import com.coderising.payroll.domain.SalesReceipt;
+import com.coderising.payroll.util.DateUtil;
+
+public class CommissionedClassification implements PaymentClassification {
+ double salary;
+ double rate;
+ public CommissionedClassification(double salary , double rate){
+ this.salary = salary;
+ this.rate = rate;
+ }
+ Map receipts;
+ @Override
+ public double calculatePay(Paycheck pc) {
+ double commission = 0.0;
+ for(SalesReceipt sr : receipts.values()){
+ if(DateUtil.between(sr.getSaleDate(), pc.getPayPeriodStartDate(),
+ pc.getPayPeriodEndDate())){
+ commission += sr.getAmount() * rate;
+ }
+ }
+ return salary + commission;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/HourlyClassification.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/HourlyClassification.java
new file mode 100644
index 0000000000..1238ac84a6
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/HourlyClassification.java
@@ -0,0 +1,43 @@
+package com.coderising.payroll.classification;
+
+import java.util.Date;
+import java.util.Map;
+
+import com.coderising.payroll.domain.Paycheck;
+import com.coderising.payroll.domain.PaymentClassification;
+import com.coderising.payroll.domain.TimeCard;
+import com.coderising.payroll.util.DateUtil;
+
+public class HourlyClassification implements PaymentClassification {
+ private double rate;
+ private Map timeCards;
+
+ public HourlyClassification(double hourlyRate) {
+ this.rate = hourlyRate;
+ }
+ public void addTimeCard(TimeCard tc){
+ timeCards.put(tc.getDate(), tc);
+ }
+ @Override
+ public double calculatePay(Paycheck pc) {
+ double totalPay = 0;
+ for(TimeCard tc : timeCards.values()){
+ if(DateUtil.between(tc.getDate(), pc.getPayPeriodStartDate(),
+ pc.getPayPeriodEndDate())){
+ totalPay += calculatePayForTimeCard(tc);
+ }
+ }
+ return totalPay;
+
+ }
+ private double calculatePayForTimeCard(TimeCard tc) {
+ int hours = tc.getHours();
+
+ if(hours > 8){
+ return 8*rate + (hours-8) * rate * 1.5;
+ } else{
+ return 8*rate;
+ }
+ }
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/SalariedClassification.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/SalariedClassification.java
new file mode 100644
index 0000000000..796aae93f1
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/classification/SalariedClassification.java
@@ -0,0 +1,16 @@
+package com.coderising.payroll.classification;
+
+import com.coderising.payroll.domain.Paycheck;
+import com.coderising.payroll.domain.PaymentClassification;
+
+public class SalariedClassification implements PaymentClassification {
+ private double salary;
+ public SalariedClassification(double salary){
+ this.salary = salary;
+ }
+ @Override
+ public double calculatePay(Paycheck pc) {
+ return salary;
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Affiliation.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Affiliation.java
new file mode 100644
index 0000000000..74a6b404bc
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Affiliation.java
@@ -0,0 +1,5 @@
+package com.coderising.payroll.domain;
+
+public interface Affiliation {
+ public double calculateDeductions(Paycheck pc);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Employee.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Employee.java
new file mode 100644
index 0000000000..204180a672
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Employee.java
@@ -0,0 +1,48 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+
+public class Employee {
+ private String id;
+ private String name;
+ private String address;
+ private Affiliation affiliation;
+
+
+ private PaymentClassification classification;
+ private PaymentSchedule schedule;
+ private PaymentMethod paymentMethod;
+
+ public Employee(String name, String address){
+ this.name = name;
+ this.address = address;
+ }
+ public boolean isPayDay(Date d) {
+ return this.schedule.isPayDate(d);
+ }
+
+ public Date getPayPeriodStartDate(Date d) {
+ return this.schedule.getPayPeriodStartDate(d);
+ }
+
+ public void payDay(Paycheck pc){
+ double grossPay = classification.calculatePay(pc);
+ double deductions = affiliation.calculateDeductions(pc);
+ double netPay = grossPay - deductions;
+ pc.setGrossPay(grossPay);
+ pc.setDeductions(deductions);
+ pc.setNetPay(netPay);
+ paymentMethod.pay(pc);
+ }
+
+ public void setClassification(PaymentClassification classification) {
+ this.classification = classification;
+ }
+ public void setSchedule(PaymentSchedule schedule) {
+ this.schedule = schedule;
+ }
+ public void setPaymentMethod(PaymentMethod paymentMethod) {
+ this.paymentMethod = paymentMethod;
+ }
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/HoldMethod.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/HoldMethod.java
new file mode 100644
index 0000000000..0ce19e2291
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/HoldMethod.java
@@ -0,0 +1,11 @@
+package com.coderising.payroll.domain;
+
+public class HoldMethod implements PaymentMethod {
+
+ @Override
+ public void pay(Paycheck pc) {
+
+
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Paycheck.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Paycheck.java
new file mode 100644
index 0000000000..6f1ff99413
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/Paycheck.java
@@ -0,0 +1,35 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+import java.util.Map;
+
+public class Paycheck {
+ private Date payPeriodStart;
+ private Date payPeriodEnd;
+ private double grossPay;
+ private double netPay;
+ private double deductions;
+ private Map itsFields;
+ public Paycheck(Date payPeriodStart, Date payPeriodEnd){
+ this.payPeriodStart = payPeriodStart;
+ this.payPeriodEnd = payPeriodEnd;
+ }
+ public void setGrossPay(double grossPay) {
+ this.grossPay = grossPay;
+
+ }
+ public void setDeductions(double deductions) {
+ this.deductions = deductions;
+ }
+ public void setNetPay(double netPay){
+ this.netPay = netPay;
+ }
+ public Date getPayPeriodEndDate() {
+
+ return this.payPeriodEnd;
+ }
+ public Date getPayPeriodStartDate() {
+
+ return this.payPeriodStart;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaydayTransaction.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaydayTransaction.java
new file mode 100644
index 0000000000..e066e46263
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaydayTransaction.java
@@ -0,0 +1,23 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+import java.util.List;
+
+import com.coderising.payroll.PayrollService;
+
+public class PaydayTransaction {
+ private Date date;
+ private PayrollService payrollService;
+
+ public void execute(){
+ List employees = payrollService.getAllEmployees();
+ for(Employee e : employees){
+ if(e.isPayDay(date)){
+ Paycheck pc = new Paycheck(e.getPayPeriodStartDate(date),date);
+ e.payDay(pc);
+ payrollService.savePaycheck(pc);
+ }
+ }
+ }
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentClassification.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentClassification.java
new file mode 100644
index 0000000000..b6f2120bdb
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentClassification.java
@@ -0,0 +1,5 @@
+package com.coderising.payroll.domain;
+
+public interface PaymentClassification {
+ public double calculatePay(Paycheck pc);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentMethod.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentMethod.java
new file mode 100644
index 0000000000..f07cc5354b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentMethod.java
@@ -0,0 +1,5 @@
+package com.coderising.payroll.domain;
+
+public interface PaymentMethod {
+ public void pay(Paycheck pc);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentSchedule.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentSchedule.java
new file mode 100644
index 0000000000..96788f4f80
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/PaymentSchedule.java
@@ -0,0 +1,8 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+
+public interface PaymentSchedule {
+ public boolean isPayDate(Date date);
+ public Date getPayPeriodStartDate( Date payPeriodEndDate);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/SalesReceipt.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/SalesReceipt.java
new file mode 100644
index 0000000000..a7b0ba41ad
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/SalesReceipt.java
@@ -0,0 +1,14 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+
+public class SalesReceipt {
+ private Date saleDate;
+ private double amount;
+ public Date getSaleDate() {
+ return saleDate;
+ }
+ public double getAmount() {
+ return amount;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/TimeCard.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/TimeCard.java
new file mode 100644
index 0000000000..ebf6e17a4c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/domain/TimeCard.java
@@ -0,0 +1,15 @@
+package com.coderising.payroll.domain;
+
+import java.util.Date;
+
+public class TimeCard {
+ private Date date;
+ private int hours;
+
+ public Date getDate() {
+ return date;
+ }
+ public int getHours() {
+ return hours;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/BiweeklySchedule.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/BiweeklySchedule.java
new file mode 100644
index 0000000000..35ec65c49c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/BiweeklySchedule.java
@@ -0,0 +1,38 @@
+package com.coderising.payroll.schedule;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.coderising.payroll.domain.PaymentSchedule;
+import com.coderising.payroll.util.DateUtil;
+
+public class BiweeklySchedule implements PaymentSchedule {
+ Date firstPayableFriday = DateUtil.parseDate("2017-6-2");
+
+ @Override
+ public boolean isPayDate(Date date) {
+
+ long interval = DateUtil.getDaysBetween(firstPayableFriday, date);
+ return interval % 14 == 0;
+ }
+
+ @Override
+ public Date getPayPeriodStartDate(Date payPeriodEndDate) {
+ return DateUtil.add(payPeriodEndDate, -13);
+
+ }
+
+ public static void main(String [] args) throws Exception{
+ BiweeklySchedule schedule = new BiweeklySchedule();
+
+ SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
+ Date d = sdf.parse("2017-06-30");
+
+ System.out.println(schedule.isPayDate(d));
+
+ System.out.println(DateUtil.isFriday(d));
+
+ System.out.println(schedule.getPayPeriodStartDate(d));
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/MonthlySchedule.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/MonthlySchedule.java
new file mode 100644
index 0000000000..dbbe732d2f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/MonthlySchedule.java
@@ -0,0 +1,20 @@
+package com.coderising.payroll.schedule;
+
+import java.util.Date;
+
+import com.coderising.payroll.domain.PaymentSchedule;
+import com.coderising.payroll.util.DateUtil;
+
+public class MonthlySchedule implements PaymentSchedule {
+
+ @Override
+ public boolean isPayDate(Date date) {
+ return DateUtil.isLastDayOfMonth(date);
+ }
+
+ @Override
+ public Date getPayPeriodStartDate(Date payPeriodEndDate) {
+ return DateUtil.getFirstDay(payPeriodEndDate);
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/WeeklySchedule.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/WeeklySchedule.java
new file mode 100644
index 0000000000..54a22ab7db
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/schedule/WeeklySchedule.java
@@ -0,0 +1,19 @@
+package com.coderising.payroll.schedule;
+
+import java.util.Date;
+
+import com.coderising.payroll.domain.PaymentSchedule;
+import com.coderising.payroll.util.DateUtil;
+
+public class WeeklySchedule implements PaymentSchedule {
+
+ @Override
+ public boolean isPayDate(Date date) {
+ return DateUtil.isFriday(date);
+ }
+ @Override
+ public Date getPayPeriodStartDate(Date payPeriodEndDate) {
+ return DateUtil.add(payPeriodEndDate, -6);
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddEmployeeTransaction.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddEmployeeTransaction.java
new file mode 100644
index 0000000000..39b268486b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddEmployeeTransaction.java
@@ -0,0 +1,29 @@
+package com.coderising.payroll.transaction;
+
+import com.coderising.payroll.domain.Employee;
+import com.coderising.payroll.domain.HoldMethod;
+import com.coderising.payroll.domain.PaymentClassification;
+import com.coderising.payroll.domain.PaymentMethod;
+import com.coderising.payroll.domain.PaymentSchedule;
+
+public abstract class AddEmployeeTransaction {
+ private String name;
+ private String address;
+ public AddEmployeeTransaction(String name,String address){
+ this.name = name;
+ this.address = address;
+ }
+ public abstract PaymentClassification getClassification();
+ public abstract PaymentSchedule getSchedule();
+
+ public void execute(){
+ PaymentClassification pc = getClassification();
+ PaymentSchedule ps = getSchedule();
+ PaymentMethod pm = new HoldMethod();
+ Employee e = new Employee(name, address);
+ e.setClassification(pc);
+ e.setSchedule(ps);
+ e.setPaymentMethod(pm);
+ //保存到数据库, 略
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddHourlyEmployeeTransaction.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddHourlyEmployeeTransaction.java
new file mode 100644
index 0000000000..2039734479
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/transaction/AddHourlyEmployeeTransaction.java
@@ -0,0 +1,25 @@
+package com.coderising.payroll.transaction;
+
+import com.coderising.payroll.classification.HourlyClassification;
+import com.coderising.payroll.domain.PaymentClassification;
+import com.coderising.payroll.domain.PaymentSchedule;
+import com.coderising.payroll.schedule.WeeklySchedule;
+
+public class AddHourlyEmployeeTransaction extends AddEmployeeTransaction{
+ private double rate;
+ AddHourlyEmployeeTransaction(String name, String address, double hourlyRate) {
+ super(name, address);
+ this.rate = hourlyRate;
+ }
+ @Override
+ public PaymentClassification getClassification() {
+ return new HourlyClassification(rate);
+ }
+
+ @Override
+ public PaymentSchedule getSchedule() {
+
+ return new WeeklySchedule();
+ }
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/util/DateUtil.java b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/util/DateUtil.java
new file mode 100644
index 0000000000..ffc26f31a1
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/com/coderising/payroll/util/DateUtil.java
@@ -0,0 +1,56 @@
+package com.coderising.payroll.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+public class DateUtil {
+ public static long getDaysBetween(Date d1, Date d2){
+
+ return (d2.getTime() - d1.getTime())/(24*60*60*1000);
+ }
+
+ public static Date parseDate(String txtDate){
+ SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
+ try {
+ return sdf.parse(txtDate);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ public static boolean isFriday(Date d){
+ Calendar calendar = Calendar.getInstance();
+ return calendar.get(Calendar.DAY_OF_WEEK) == 5;
+ }
+
+ public static Date add(Date d, int days){
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(d);
+ calendar.add(Calendar.DATE, days);
+ return calendar.getTime();
+ }
+
+ public static boolean isLastDayOfMonth(Date d){
+ Calendar calendar=Calendar.getInstance();
+ calendar.setTime(d);
+ return calendar.get(Calendar.DATE)==calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ }
+ public static Date getFirstDay(Date d){
+ Calendar calendar=Calendar.getInstance();
+ calendar.setTime(d);
+ int day = calendar.get(Calendar.DATE);
+ calendar.add(Calendar.DATE, -(day-1));
+ return calendar.getTime();
+ }
+ public static void main(String [] args) throws Exception{
+ System.out.println(DateUtil.isLastDayOfMonth(DateUtil.parseDate("2017-6-29")));
+
+ System.out.println(DateUtil.getFirstDay(DateUtil.parseDate("2017-6-30")));
+ }
+
+ public static boolean between(Date d, Date date1, Date date2){
+ return d.after(date1) && d.before(date2);
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/RepeatedTest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/RepeatedTest.java
new file mode 100644
index 0000000000..f6250ee426
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/RepeatedTest.java
@@ -0,0 +1,32 @@
+package org.litejunit.extension;
+
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestResult;
+
+/**
+ * A Decorator that runs a test repeatedly.
+ *
+ */
+public class RepeatedTest extends TestDecorator {
+ private int fTimesRepeat;
+
+ public RepeatedTest(Test test, int repeat) {
+ super(test);
+ if (repeat < 0)
+ throw new IllegalArgumentException("Repetition count must be > 0");
+ fTimesRepeat= repeat;
+ }
+ public int countTestCases() {
+ return super.countTestCases()*fTimesRepeat;
+ }
+ public void run(TestResult result) {
+ for (int i= 0; i < fTimesRepeat; i++) {
+ if (result.shouldStop())
+ break;
+ super.run(result);
+ }
+ }
+ public String toString() {
+ return super.toString()+"(repeated)";
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestDecorator.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestDecorator.java
new file mode 100644
index 0000000000..556d05cbbb
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestDecorator.java
@@ -0,0 +1,40 @@
+package org.litejunit.extension;
+
+import org.litejunit.v2.Assert;
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestResult;
+
+/**
+ * A Decorator for Tests. Use TestDecorator as the base class
+ * for defining new test decorators. Test decorator subclasses
+ * can be introduced to add behaviour before or after a test
+ * is run.
+ *
+ */
+public class TestDecorator extends Assert implements Test {
+ protected Test test;
+
+ public TestDecorator(Test test) {
+ this.test= test;
+ }
+ /**
+ * The basic run behaviour.
+ */
+ public void basicRun(TestResult result) {
+ test.run(result);
+ }
+ public int countTestCases() {
+ return test.countTestCases();
+ }
+ public void run(TestResult result) {
+ basicRun(result);
+ }
+
+ public String toString() {
+ return test.toString();
+ }
+
+ public Test getTest() {
+ return test;
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestSetup.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestSetup.java
new file mode 100644
index 0000000000..7a133a798c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/extension/TestSetup.java
@@ -0,0 +1,39 @@
+package org.litejunit.extension;
+
+import org.litejunit.v2.Protectable;
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestResult;
+
+/**
+ * A Decorator to set up and tear down additional fixture state.
+ * Subclass TestSetup and insert it into your tests when you want
+ * to set up additional state once before the tests are run.
+ */
+public class TestSetup extends TestDecorator {
+
+ public TestSetup(Test test) {
+ super(test);
+ }
+ public void run(final TestResult result) {
+ Protectable p= new Protectable() {
+ public void protect() throws Exception {
+ setUp();
+ basicRun(result);
+ tearDown();
+ }
+ };
+ result.runProtected(this, p);
+ }
+ /**
+ * Sets up the fixture. Override to set up additional fixture
+ * state.
+ */
+ protected void setUp() throws Exception {
+ }
+ /**
+ * Tears down the fixture. Override to tear down the additional
+ * fixture state.
+ */
+ protected void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/AllTest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/AllTest.java
new file mode 100644
index 0000000000..2c4d6b3dca
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/AllTest.java
@@ -0,0 +1,43 @@
+package org.litejunit.sample;
+
+import org.litejunit.extension.RepeatedTest;
+import org.litejunit.extension.TestSetup;
+import org.litejunit.sample.calculator.CalculatorSuite;
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestSuite;
+
+
+public class AllTest {
+ /*public static Test suite(){
+
+ TestSuite suite= new TestSuite("All Test");
+ suite.addTest(CalculatorSuite.suite());
+ suite.addTestSuite(PersonTest.class);
+ return suite;
+
+ }*/
+
+ public static Test suite(){
+
+ TestSuite suite= new TestSuite("All Test");
+ suite.addTest(CalculatorSuite.suite());
+ suite.addTest(new RepeatedTest(new TestSuite(PersonTest.class), 2));
+ return new OverallTestSetup(suite);
+ }
+
+
+ static class OverallTestSetup extends TestSetup{
+
+ public OverallTestSetup(Test test) {
+ super(test);
+
+ }
+ protected void setUp() throws Exception {
+ System.out.println("this is overall testsetup");
+ }
+ protected void tearDown() throws Exception {
+ System.out.println("this is overall teardown");
+ }
+
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/PersonTest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/PersonTest.java
new file mode 100644
index 0000000000..2e76ea26ae
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/PersonTest.java
@@ -0,0 +1,38 @@
+package org.litejunit.sample;
+
+import org.litejunit.v2.TestCase;
+
+public class PersonTest extends TestCase {
+
+ Person p = null;
+ protected void setUp() {
+ p = new Person("andy",30);
+ }
+ public PersonTest(String name) {
+ super(name);
+ }
+ public void testAge(){
+ this.assertEquals(30, p.getAge());
+ }
+ public void testName(){
+ this.assertEquals("andy", p.getName());
+ }
+}
+class Person{
+ private String name;
+ private int age;
+
+ public Person(String name, int age) {
+
+ this.name = name;
+ this.age = age;
+ }
+ public String getName() {
+ return name;
+ }
+ public int getAge() {
+ return age;
+ }
+
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/Calculator.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/Calculator.java
new file mode 100644
index 0000000000..ed0a69959a
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/Calculator.java
@@ -0,0 +1,22 @@
+package org.litejunit.sample.calculator;
+
+public class Calculator {
+
+ private int result = 0;
+ public void add(int x){
+ result += x;
+ }
+ public void subtract(int x){
+ result -=x;
+ }
+
+ public int getResult(){
+ return this.result;
+ }
+ public static void main(String[] args){
+ Calculator calculator = new Calculator();
+ calculator.add(10);
+ calculator.subtract(5);
+ System.out.println(calculator.getResult());
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorSuite.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorSuite.java
new file mode 100644
index 0000000000..1deec69c52
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorSuite.java
@@ -0,0 +1,12 @@
+package org.litejunit.sample.calculator;
+
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestSuite;
+
+public class CalculatorSuite {
+ public static Test suite(){
+ TestSuite suite= new TestSuite("Calculator All Test");
+ suite.addTestSuite(CalculatorTest.class);
+ return suite;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorTest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorTest.java
new file mode 100644
index 0000000000..39f1d2433b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/sample/calculator/CalculatorTest.java
@@ -0,0 +1,59 @@
+package org.litejunit.sample.calculator;
+
+import org.litejunit.v2.TestCase;
+
+public class CalculatorTest extends TestCase {
+ public CalculatorTest(String name) {
+ super(name);
+
+ }
+ Calculator calculator =null;
+ public void setUp(){
+ calculator = new Calculator();
+ }
+ public void tearDown(){
+ calculator = null;
+ }
+ public void testAdd(){
+
+ calculator.add(10);
+ assertEquals(5,calculator.getResult());
+ }
+ public void testSubtract(){
+ calculator.add(10);
+ calculator.subtract(5);
+ throw new RuntimeException("this is a test");
+ //assertEquals(5,calculator.getResult());
+ }
+
+ public static void main(String[] args){
+ /*{
+ TestCase tc1 = new CalculatorTest("testAdd"){
+ protected void runTest() {
+ testAdd();
+ }
+ };
+
+ TestCase tc2 = new CalculatorTest("testSubtract"){
+ protected void runTest() {
+ testSubtract();
+ }
+ };
+ tc1.run();
+ tc2.run();
+ }
+
+
+ TestSuite ts = new TestSuite();
+ ts.addTest(new CalculatorTest("testAdd"));
+ ts.addTest(new CalculatorTest("testSubtract"));
+
+
+ {
+ TestCase tc1 = new CalculatorTest("test1");
+ TestCase tc2 = new CalculatorTest("test2");
+ tc1.run();
+ tc2.run();
+ }*/
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Assert.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Assert.java
new file mode 100644
index 0000000000..07a3c1a22b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Assert.java
@@ -0,0 +1,225 @@
+package org.litejunit.v1;
+
+/**
+ * A set of assert methods.
+ */
+
+public class Assert {
+ /**
+ * Protect constructor since it is a static only class
+ */
+ protected Assert() {
+ }
+
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError with the given message.
+ */
+ static public void assertTrue(String message, boolean condition) {
+ if (!condition)
+ fail(message);
+ }
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError.
+ */
+ static public void assertTrue(boolean condition) {
+ assertTrue(null, condition);
+ }
+ /**
+ * Fails a test with the given message.
+ */
+ static public void fail(String message) {
+ throw new AssertionFailedError(message);
+ }
+ /**
+ * Fails a test with no message.
+ */
+ static public void fail() {
+ fail(null);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertEquals(String message, Object expected, Object actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && expected.equals(actual))
+ return;
+ failNotEquals(message, expected, actual);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertEquals(Object expected, Object actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two doubles are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(String message, double expected, double actual, double delta) {
+ // handle infinity specially since subtracting to infinite values gives NaN and the
+ // the following test fails
+ if (Double.isInfinite(expected)) {
+ if (!(expected == actual))
+ failNotEquals(message, new Double(expected), new Double(actual));
+ } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
+ failNotEquals(message, new Double(expected), new Double(actual));
+ }
+ /**
+ * Asserts that two doubles are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(double expected, double actual, double delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * Asserts that two floats are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(String message, float expected, float actual, float delta) {
+ // handle infinity specially since subtracting to infinite values gives NaN and the
+ // the following test fails
+ if (Float.isInfinite(expected)) {
+ if (!(expected == actual))
+ failNotEquals(message, new Float(expected), new Float(actual));
+ } else if (!(Math.abs(expected-actual) <= delta))
+ failNotEquals(message, new Float(expected), new Float(actual));
+ }
+ /**
+ * Asserts that two floats are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(float expected, float actual, float delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * Asserts that two longs are equal.
+ */
+ static public void assertEquals(String message, long expected, long actual) {
+ assertEquals(message, new Long(expected), new Long(actual));
+ }
+ /**
+ * Asserts that two longs are equal.
+ */
+ static public void assertEquals(long expected, long actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two booleans are equal.
+ */
+ static public void assertEquals(String message, boolean expected, boolean actual) {
+ assertEquals(message, new Boolean(expected), new Boolean(actual));
+ }
+ /**
+ * Asserts that two booleans are equal.
+ */
+ static public void assertEquals(boolean expected, boolean actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two bytes are equal.
+ */
+ static public void assertEquals(String message, byte expected, byte actual) {
+ assertEquals(message, new Byte(expected), new Byte(actual));
+ }
+ /**
+ * Asserts that two bytes are equal.
+ */
+ static public void assertEquals(byte expected, byte actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two chars are equal.
+ */
+ static public void assertEquals(String message, char expected, char actual) {
+ assertEquals(message, new Character(expected), new Character(actual));
+ }
+ /**
+ * Asserts that two chars are equal.
+ */
+ static public void assertEquals(char expected, char actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two shorts are equal.
+ */
+ static public void assertEquals(String message, short expected, short actual) {
+ assertEquals(message, new Short(expected), new Short(actual));
+ }
+ /**
+ * Asserts that two shorts are equal.
+ */
+ static public void assertEquals(short expected, short actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two ints are equal.
+ */
+ static public void assertEquals(String message, int expected, int actual) {
+ assertEquals(message, new Integer(expected), new Integer(actual));
+ }
+ /**
+ * Asserts that two ints are equal.
+ */
+ static public void assertEquals(int expected, int actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that an object isn't null.
+ */
+ static public void assertNotNull(Object object) {
+ assertNotNull(null, object);
+ }
+ /**
+ * Asserts that an object isn't null.
+ */
+ static public void assertNotNull(String message, Object object) {
+ assertTrue(message, object != null);
+ }
+ /**
+ * Asserts that an object is null.
+ */
+ static public void assertNull(Object object) {
+ assertNull(null, object);
+ }
+ /**
+ * Asserts that an object is null.
+ */
+ static public void assertNull(String message, Object object) {
+ assertTrue(message, object == null);
+ }
+ /**
+ * Asserts that two objects refer to the same object. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertSame(String message, Object expected, Object actual) {
+ if (expected == actual)
+ return;
+ failNotSame(message, expected, actual);
+ }
+ /**
+ * Asserts that two objects refer to the same object. If they are not
+ * the same an AssertionFailedError is thrown.
+ */
+ static public void assertSame(Object expected, Object actual) {
+ assertSame(null, expected, actual);
+ }
+
+ static private void failNotEquals(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected:<"+expected+"> but was:<"+actual+">");
+ }
+
+ static private void failNotSame(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected same");
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/AssertionFailedError.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/AssertionFailedError.java
new file mode 100644
index 0000000000..05e786ea47
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/AssertionFailedError.java
@@ -0,0 +1,13 @@
+package org.litejunit.v1;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends Error {
+
+ public AssertionFailedError () {
+ }
+ public AssertionFailedError (String message) {
+ super (message);
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Calculator.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Calculator.java
new file mode 100644
index 0000000000..f1245ff3a6
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Calculator.java
@@ -0,0 +1,22 @@
+package org.litejunit.v1;
+
+public class Calculator {
+
+ private int result = 0;
+ public void add(int x){
+ result += x;
+ }
+ public void subtract(int x){
+ result -=x;
+ }
+
+ public int getResult(){
+ return this.result;
+ }
+ public static void main(String[] args){
+ Calculator calculator = new Calculator();
+ calculator.add(10);
+ calculator.subtract(5);
+ System.out.println(calculator.getResult());
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/CalculatorTest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/CalculatorTest.java
new file mode 100644
index 0000000000..3460528043
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/CalculatorTest.java
@@ -0,0 +1,65 @@
+package org.litejunit.v1;
+
+
+public class CalculatorTest extends TestCase {
+ public CalculatorTest(String name) {
+ super(name);
+
+ }
+ Calculator calculator =null;
+ public void setUp(){
+ calculator = new Calculator();
+ }
+ public void tearDown(){
+ calculator = null;
+ }
+ public void testAdd(){
+
+ calculator.add(10);
+ assertEquals(10,calculator.getResult());
+ }
+ public void testSubtract(){
+ calculator.add(10);
+ calculator.subtract(5);
+ assertEquals(4,calculator.getResult());
+ }
+
+ public static void main(String[] args){
+ TestSuite ts = new TestSuite(CalculatorTest.class);
+ TestResult tr = new TestResult();
+ ts.run(tr);
+ System.out.println(tr.wasSuccessful());
+ for(TestFailure failure : tr.failures){
+ System.err.println(failure);
+ }
+
+ /*{
+ TestCase tc1 = new CalculatorTest("testAdd"){
+ protected void runTest() {
+ testAdd();
+ }
+ };
+
+ TestCase tc2 = new CalculatorTest("testSubtract"){
+ protected void runTest() {
+ testSubtract();
+ }
+ };
+ tc1.run();
+ tc2.run();
+ }
+
+
+ TestSuite ts = new TestSuite();
+ ts.addTest(new CalculatorTest("testAdd"));
+ ts.addTest(new CalculatorTest("testSubtract"));
+
+
+ {
+ TestCase tc1 = new CalculatorTest("test1");
+ TestCase tc2 = new CalculatorTest("test2");
+ tc1.run();
+ tc2.run();
+ }*/
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Test.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Test.java
new file mode 100644
index 0000000000..3d870cf637
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/Test.java
@@ -0,0 +1,6 @@
+package org.litejunit.v1;
+
+public interface Test {
+ public abstract int countTestCases();
+ public void run(TestResult tr);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestCase.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestCase.java
new file mode 100644
index 0000000000..d9cebd263b
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestCase.java
@@ -0,0 +1,63 @@
+package org.litejunit.v1;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+
+
+public abstract class TestCase extends Assert implements Test {
+ private String name;
+
+
+ public TestCase(String name) {
+ this.name = name;
+ }
+
+ public int countTestCases() {
+ return 1;
+ }
+
+ protected void runTest() throws Throwable{
+ Method runMethod= null;
+ try {
+ runMethod= getClass().getMethod(name, null);
+ } catch (NoSuchMethodException e) {
+ fail("Method \""+name+"\" not found");
+ }
+ if (!Modifier.isPublic(runMethod.getModifiers())) {
+ fail("Method \""+name+"\" should be public");
+ }
+
+ try {
+ runMethod.invoke(this, new Class[0]);
+ }
+ catch (InvocationTargetException e) {
+ e.fillInStackTrace();
+ throw e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ e.fillInStackTrace();
+ throw e;
+ }
+ }
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void run(TestResult tr) {
+ tr.run(this);
+ }
+ public void doRun() throws Throwable{
+ setUp();
+ try{
+ runTest();
+ }
+ finally{
+ tearDown();
+ }
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestFailure.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestFailure.java
new file mode 100644
index 0000000000..1ac44256a4
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestFailure.java
@@ -0,0 +1,39 @@
+package org.litejunit.v1;
+
+/**
+ * A TestFailure collects a failed test together with
+ * the caught exception.
+ * @see TestResult
+ */
+public class TestFailure {
+ protected Test failedTest;
+ protected Throwable thrownException;
+
+ /**
+ * Constructs a TestFailure with the given test and exception.
+ */
+ public TestFailure(Test failedTest, Throwable thrownException) {
+ this.failedTest= failedTest;
+ this.thrownException= thrownException;
+ }
+ /**
+ * Gets the failed test.
+ */
+ public Test failedTest() {
+ return failedTest;
+ }
+ /**
+ * Gets the thrown exception.
+ */
+ public Throwable thrownException() {
+ return thrownException;
+ }
+ /**
+ * Returns a short description of the failure.
+ */
+ public String toString() {
+ StringBuffer buffer= new StringBuffer();
+ buffer.append(failedTest+": "+thrownException.getMessage());
+ return buffer.toString();
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestResult.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestResult.java
new file mode 100644
index 0000000000..a9e8c2b439
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestResult.java
@@ -0,0 +1,95 @@
+package org.litejunit.v1;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+
+
+
+public class TestResult extends Object {
+ protected List failures;
+ protected List errors;
+
+ protected int testCount;
+ private boolean stop;
+
+ public TestResult() {
+ failures= new ArrayList<>();
+ errors= new ArrayList<>();
+
+ testCount= 0;
+ stop= false;
+ }
+
+ public void addError(Test test, Throwable t) {
+ errors.add(new TestFailure(test, t));
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ failures.add(new TestFailure(test, t));
+ }
+
+ public void startTest(Test test) {
+ int count= test.countTestCases();
+ testCount+= count;
+ }
+ public void endTest(Test test) {
+ }
+
+ /**
+ * Runs a TestCase.
+ */
+ protected void run(final TestCase test) {
+ startTest(test);
+ try {
+ test.doRun();
+ }
+ catch (AssertionFailedError e) {
+ addFailure(test, e);
+ }
+ catch (Throwable e) {
+ addError(test, e);
+ }
+
+ endTest(test);
+ }
+ /**
+ * Gets the number of run tests.
+ */
+ public int runCount() {
+ return testCount;
+ }
+
+
+ public boolean shouldStop() {
+ return stop;
+ }
+
+ public void stop() {
+ stop= true;
+ }
+
+ public int errorCount() {
+ return errors.size();
+ }
+
+ public Iterator errors() {
+ return errors.iterator();
+ }
+
+ public int failureCount() {
+ return failures.size();
+ }
+
+ public Iterator failures() {
+ return failures.iterator();
+ }
+ /**
+ * Returns whether the entire test was successful or not.
+ */
+ public boolean wasSuccessful() {
+ return this.failureCount() == 0 && this.errorCount() == 0;
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestSuite.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestSuite.java
new file mode 100644
index 0000000000..ad0af20ffd
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v1/TestSuite.java
@@ -0,0 +1,130 @@
+package org.litejunit.v1;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+
+
+
+public class TestSuite extends Assert implements Test {
+ private List tests= new ArrayList<>(10);
+ private String name;
+ public TestSuite(){
+
+ }
+ public TestSuite(final Class> theClass) {
+ this.name= theClass.getName();
+ Constructor> constructor= null;
+ try {
+ constructor= getConstructor(theClass);
+ } catch (NoSuchMethodException e) {
+ addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name)"));
+ return;
+ }
+
+ if (!Modifier.isPublic(theClass.getModifiers())) {
+ addTest(warning("Class "+theClass.getName()+" is not public"));
+ return;
+ }
+
+ Vector names= new Vector<>();
+ Method[] methods= theClass.getDeclaredMethods();
+ for (int i= 0; i < methods.length; i++) {
+ addTestMethod(methods[i], names, constructor);
+ }
+
+ if (tests.size() == 0)
+ addTest(warning("No tests found in "+theClass.getName()));
+ }
+
+ private Constructor> getConstructor(Class> theClass) throws NoSuchMethodException {
+ Class>[] args= { String.class };
+ return theClass.getConstructor(args);
+ }
+ private void addTestMethod(Method m, Vector names, Constructor> constructor) {
+ String name= m.getName();
+ if (names.contains(name))
+ return;
+ if (isPublicTestMethod(m)) {
+ names.addElement(name);
+
+ Object[] args= new Object[]{name};
+ try {
+ addTest((Test)constructor.newInstance(args));
+ } catch (InstantiationException e) {
+ addTest(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
+ } catch (InvocationTargetException e) {
+ addTest(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
+ } catch (IllegalAccessException e) {
+ addTest(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
+ }
+
+ } else { // almost a test method
+ if (isTestMethod(m))
+ addTest(warning("Test method isn't public: "+m.getName()));
+ }
+ }
+ private boolean isPublicTestMethod(Method m) {
+ return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+ }
+ private boolean isTestMethod(Method m) {
+ String name= m.getName();
+ Class>[] parameters= m.getParameterTypes();
+ Class> returnType= m.getReturnType();
+ return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
+ }
+ public void addTest(Test test) {
+ tests.add(test);
+ }
+
+ private Test warning(final String message) {
+ return new TestCase("warning") {
+ public void doRun() {
+ fail(message);
+ }
+ };
+ }
+ private String exceptionToString(Throwable t) {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ t.printStackTrace(writer);
+ return stringWriter.toString();
+
+ }
+
+
+
+ @Override
+ public void run(TestResult result) {
+ for (Iterator e= tests(); e.hasNext(); ) {
+ if (result.shouldStop() ){
+ break;
+ }
+ Test test= (Test)e.next();
+ test.run(result);
+ }
+
+ }
+
+ public int countTestCases() {
+ int count= 0;
+
+ for (Iterator e= tests(); e.hasNext(); ) {
+ Test test= e.next();
+ count= count + test.countTestCases();
+ }
+ return count;
+ }
+ public Iterator tests() {
+ return tests.iterator();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Assert.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Assert.java
new file mode 100644
index 0000000000..4e5a9920bd
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Assert.java
@@ -0,0 +1,243 @@
+package org.litejunit.v2;
+
+/**
+ * A set of assert methods.
+ */
+
+public class Assert {
+ /**
+ * Protect constructor since it is a static only class
+ */
+ protected Assert() {
+ }
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError with the given message.
+ * @deprecated use assertTrue
+ */
+ /*static public void assert(String message, boolean condition) {
+ if (!condition)
+ fail(message);
+ }*/
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError.
+ * @deprecated use assertTrue
+ *
+ */
+ /*static public void assert(boolean condition) {
+ assert(null, condition);
+ }
+*/
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError with the given message.
+ */
+ static public void assertTrue(String message, boolean condition) {
+ if (!condition)
+ fail(message);
+ }
+ /**
+ * Asserts that a condition is true. If it isn't it throws
+ * an AssertionFailedError.
+ */
+ static public void assertTrue(boolean condition) {
+ assertTrue(null, condition);
+ }
+ /**
+ * Fails a test with the given message.
+ */
+ static public void fail(String message) {
+ throw new AssertionFailedError(message);
+ }
+ /**
+ * Fails a test with no message.
+ */
+ static public void fail() {
+ fail(null);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertEquals(String message, Object expected, Object actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && expected.equals(actual))
+ return;
+ failNotEquals(message, expected, actual);
+ }
+ /**
+ * Asserts that two objects are equal. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertEquals(Object expected, Object actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two doubles are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(String message, double expected, double actual, double delta) {
+ // handle infinity specially since subtracting to infinite values gives NaN and the
+ // the following test fails
+ if (Double.isInfinite(expected)) {
+ if (!(expected == actual))
+ failNotEquals(message, new Double(expected), new Double(actual));
+ } else if (!(Math.abs(expected-actual) <= delta)) // Because comparison with NaN always returns false
+ failNotEquals(message, new Double(expected), new Double(actual));
+ }
+ /**
+ * Asserts that two doubles are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(double expected, double actual, double delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * Asserts that two floats are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(String message, float expected, float actual, float delta) {
+ // handle infinity specially since subtracting to infinite values gives NaN and the
+ // the following test fails
+ if (Float.isInfinite(expected)) {
+ if (!(expected == actual))
+ failNotEquals(message, new Float(expected), new Float(actual));
+ } else if (!(Math.abs(expected-actual) <= delta))
+ failNotEquals(message, new Float(expected), new Float(actual));
+ }
+ /**
+ * Asserts that two floats are equal concerning a delta. If the expected
+ * value is infinity then the delta value is ignored.
+ */
+ static public void assertEquals(float expected, float actual, float delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+ /**
+ * Asserts that two longs are equal.
+ */
+ static public void assertEquals(String message, long expected, long actual) {
+ assertEquals(message, new Long(expected), new Long(actual));
+ }
+ /**
+ * Asserts that two longs are equal.
+ */
+ static public void assertEquals(long expected, long actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two booleans are equal.
+ */
+ static public void assertEquals(String message, boolean expected, boolean actual) {
+ assertEquals(message, new Boolean(expected), new Boolean(actual));
+ }
+ /**
+ * Asserts that two booleans are equal.
+ */
+ static public void assertEquals(boolean expected, boolean actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two bytes are equal.
+ */
+ static public void assertEquals(String message, byte expected, byte actual) {
+ assertEquals(message, new Byte(expected), new Byte(actual));
+ }
+ /**
+ * Asserts that two bytes are equal.
+ */
+ static public void assertEquals(byte expected, byte actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two chars are equal.
+ */
+ static public void assertEquals(String message, char expected, char actual) {
+ assertEquals(message, new Character(expected), new Character(actual));
+ }
+ /**
+ * Asserts that two chars are equal.
+ */
+ static public void assertEquals(char expected, char actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two shorts are equal.
+ */
+ static public void assertEquals(String message, short expected, short actual) {
+ assertEquals(message, new Short(expected), new Short(actual));
+ }
+ /**
+ * Asserts that two shorts are equal.
+ */
+ static public void assertEquals(short expected, short actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that two ints are equal.
+ */
+ static public void assertEquals(String message, int expected, int actual) {
+ assertEquals(message, new Integer(expected), new Integer(actual));
+ }
+ /**
+ * Asserts that two ints are equal.
+ */
+ static public void assertEquals(int expected, int actual) {
+ assertEquals(null, expected, actual);
+ }
+ /**
+ * Asserts that an object isn't null.
+ */
+ static public void assertNotNull(Object object) {
+ assertNotNull(null, object);
+ }
+ /**
+ * Asserts that an object isn't null.
+ */
+ static public void assertNotNull(String message, Object object) {
+ assertTrue(message, object != null);
+ }
+ /**
+ * Asserts that an object is null.
+ */
+ static public void assertNull(Object object) {
+ assertNull(null, object);
+ }
+ /**
+ * Asserts that an object is null.
+ */
+ static public void assertNull(String message, Object object) {
+ assertTrue(message, object == null);
+ }
+ /**
+ * Asserts that two objects refer to the same object. If they are not
+ * an AssertionFailedError is thrown.
+ */
+ static public void assertSame(String message, Object expected, Object actual) {
+ if (expected == actual)
+ return;
+ failNotSame(message, expected, actual);
+ }
+ /**
+ * Asserts that two objects refer to the same object. If they are not
+ * the same an AssertionFailedError is thrown.
+ */
+ static public void assertSame(Object expected, Object actual) {
+ assertSame(null, expected, actual);
+ }
+
+ static private void failNotEquals(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected:<"+expected+"> but was:<"+actual+">");
+ }
+
+ static private void failNotSame(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message+" ";
+ fail(formatted+"expected same");
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/AssertionFailedError.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/AssertionFailedError.java
new file mode 100644
index 0000000000..49ebf0955e
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/AssertionFailedError.java
@@ -0,0 +1,13 @@
+package org.litejunit.v2;
+
+/**
+ * Thrown when an assertion failed.
+ */
+public class AssertionFailedError extends Error {
+
+ public AssertionFailedError () {
+ }
+ public AssertionFailedError (String message) {
+ super (message);
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Protectable.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Protectable.java
new file mode 100644
index 0000000000..f43f7d8e01
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Protectable.java
@@ -0,0 +1,14 @@
+package org.litejunit.v2;
+
+/**
+ * A Protectable can be run and can throw a Throwable.
+ *
+ * @see TestResult
+ */
+public interface Protectable {
+
+ /**
+ * Run the the following method protected.
+ */
+ public abstract void protect() throws Throwable;
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Test.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Test.java
new file mode 100644
index 0000000000..73de6a2e25
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/Test.java
@@ -0,0 +1,6 @@
+package org.litejunit.v2;
+
+public interface Test {
+ public abstract int countTestCases();
+ public void run(TestResult tr);
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestCase.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestCase.java
new file mode 100644
index 0000000000..4f704d2866
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestCase.java
@@ -0,0 +1,64 @@
+package org.litejunit.v2;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+
+
+public abstract class TestCase extends Assert implements Test {
+ private String name;
+
+
+ public TestCase(String name) {
+ this.name = name;
+ }
+
+
+ public int countTestCases() {
+ return 1;
+ }
+
+ protected void runTest() throws Throwable{
+ Method runMethod= null;
+ try {
+ runMethod= getClass().getMethod(name, null);
+ } catch (NoSuchMethodException e) {
+ fail("Method \""+name+"\" not found");
+ }
+ if (!Modifier.isPublic(runMethod.getModifiers())) {
+ fail("Method \""+name+"\" should be public");
+ }
+
+ try {
+ runMethod.invoke(this, new Class[0]);
+ }
+ catch (InvocationTargetException e) {
+ e.fillInStackTrace();
+ throw e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ e.fillInStackTrace();
+ throw e;
+ }
+ }
+
+ protected void setUp() {
+ }
+
+ protected void tearDown() {
+ }
+
+ public void run(TestResult tr) {
+ tr.run(this);
+ }
+ public void doRun() throws Throwable{
+ setUp();
+ try{
+ runTest();
+ }
+ finally{
+ tearDown();
+ }
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestFailure.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestFailure.java
new file mode 100644
index 0000000000..c40f6f89e0
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestFailure.java
@@ -0,0 +1,39 @@
+package org.litejunit.v2;
+
+/**
+ * A TestFailure collects a failed test together with
+ * the caught exception.
+ * @see TestResult
+ */
+public class TestFailure {
+ protected Test failedTest;
+ protected Throwable thrownException;
+
+ /**
+ * Constructs a TestFailure with the given test and exception.
+ */
+ public TestFailure(Test failedTest, Throwable thrownException) {
+ this.failedTest= failedTest;
+ this.thrownException= thrownException;
+ }
+ /**
+ * Gets the failed test.
+ */
+ public Test failedTest() {
+ return failedTest;
+ }
+ /**
+ * Gets the thrown exception.
+ */
+ public Throwable thrownException() {
+ return thrownException;
+ }
+ /**
+ * Returns a short description of the failure.
+ */
+ public String toString() {
+ StringBuffer buffer= new StringBuffer();
+ buffer.append(failedTest+": "+thrownException.getMessage());
+ return buffer.toString();
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestListener.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestListener.java
new file mode 100644
index 0000000000..412febcc55
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestListener.java
@@ -0,0 +1,15 @@
+package org.litejunit.v2;
+
+/**
+ * A Listener for test progress
+ */
+public interface TestListener {
+
+ public void addError(Test test, Throwable t);
+
+ public void addFailure(Test test, AssertionFailedError t);
+
+ public void endTest(Test test);
+
+ public void startTest(Test test);
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestResult.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestResult.java
new file mode 100644
index 0000000000..6fb789a495
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestResult.java
@@ -0,0 +1,121 @@
+package org.litejunit.v2;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+public class TestResult extends Object {
+ protected List failures;
+ protected List errors;
+ protected List listeners;
+ protected int testCount;
+ private boolean stop;
+
+ public TestResult() {
+ failures= new ArrayList<>();
+ errors= new ArrayList<>();
+ listeners = new ArrayList<>();
+ testCount= 0;
+ stop= false;
+ }
+
+ public void addError(Test test, Throwable t) {
+ errors.add(new TestFailure(test, t));
+ for(TestListener listener: listeners){
+ listener.addError(test, t);
+ }
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ failures.add(new TestFailure(test, t));
+ for(TestListener listener: listeners){
+ listener.addFailure(test, t);
+ }
+ }
+
+ public void startTest(Test test) {
+ int count= test.countTestCases();
+ testCount+= count;
+ for(TestListener listener: listeners){
+ listener.startTest(test);
+ }
+ }
+ public void endTest(Test test) {
+ for(TestListener listener: listeners){
+ listener.endTest(test);
+ }
+ }
+
+ /**
+ * Runs a TestCase.
+ */
+ protected void run(final TestCase test) {
+ startTest(test);
+ try {
+ test.doRun();
+ }
+ catch (AssertionFailedError e) {
+ addFailure(test, e);
+ }
+ catch (Throwable e) {
+ addError(test, e);
+ }
+
+ endTest(test);
+ }
+ /**
+ * Gets the number of run tests.
+ */
+ public int runCount() {
+ return testCount;
+ }
+ public void runProtected(final Test test, Protectable p) {
+ try {
+ p.protect();
+ }
+ catch (AssertionFailedError e) {
+ addFailure(test, e);
+ }
+ catch (Throwable e) {
+ addError(test, e);
+ }
+ }
+
+ public boolean shouldStop() {
+ return stop;
+ }
+
+ public void stop() {
+ stop= true;
+ }
+
+ public int errorCount() {
+ return errors.size();
+ }
+
+ public Iterator errors() {
+ return errors.iterator();
+ }
+
+ public int failureCount() {
+ return failures.size();
+ }
+
+ public Iterator failures() {
+ return failures.iterator();
+ }
+ /**
+ * Returns whether the entire test was successful or not.
+ */
+ public boolean wasSuccessful() {
+ return this.failureCount() == 0 && this.errorCount() == 0;
+ }
+ public void addListener(TestListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(TestListener listener) {
+ listeners.remove(listener);
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestSuite.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestSuite.java
new file mode 100644
index 0000000000..9ad0a05433
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/TestSuite.java
@@ -0,0 +1,137 @@
+package org.litejunit.v2;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+
+
+
+
+
+public class TestSuite extends Assert implements Test {
+ private List tests= new ArrayList<>(10);
+ private String name;
+ public TestSuite(){
+
+ }
+ public TestSuite(final Class> theClass) {
+ this.name= theClass.getName();
+ Constructor> constructor= null;
+ try {
+ constructor= getConstructor(theClass);
+ } catch (NoSuchMethodException e) {
+ addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name)"));
+ return;
+ }
+
+ if (!Modifier.isPublic(theClass.getModifiers())) {
+ addTest(warning("Class "+theClass.getName()+" is not public"));
+ return;
+ }
+
+ Vector names= new Vector<>();
+ Method[] methods= theClass.getDeclaredMethods();
+ for (int i= 0; i < methods.length; i++) {
+ addTestMethod(methods[i], names, constructor);
+ }
+
+ if (tests.size() == 0)
+ addTest(warning("No tests found in "+theClass.getName()));
+ }
+
+ public TestSuite(String name) {
+ this.name = name;
+ }
+ private Constructor> getConstructor(Class> theClass) throws NoSuchMethodException {
+ Class>[] args= { String.class };
+ return theClass.getConstructor(args);
+ }
+ private void addTestMethod(Method m, Vector names, Constructor> constructor) {
+ String name= m.getName();
+ if (names.contains(name))
+ return;
+ if (isPublicTestMethod(m)) {
+ names.addElement(name);
+
+ Object[] args= new Object[]{name};
+ try {
+ addTest((Test)constructor.newInstance(args));
+ } catch (InstantiationException e) {
+ addTest(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")"));
+ } catch (InvocationTargetException e) {
+ addTest(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")"));
+ } catch (IllegalAccessException e) {
+ addTest(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")"));
+ }
+
+ } else { // almost a test method
+ if (isTestMethod(m))
+ addTest(warning("Test method isn't public: "+m.getName()));
+ }
+ }
+ private boolean isPublicTestMethod(Method m) {
+ return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
+ }
+ private boolean isTestMethod(Method m) {
+ String name= m.getName();
+ Class>[] parameters= m.getParameterTypes();
+ Class> returnType= m.getReturnType();
+ return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
+ }
+ public void addTest(Test test) {
+ tests.add(test);
+ }
+ public void addTestSuite(Class testClass) {
+ addTest(new TestSuite(testClass));
+ }
+ private Test warning(final String message) {
+ return new TestCase("warning") {
+ public void doRun() {
+ fail(message);
+ }
+ };
+ }
+ private String exceptionToString(Throwable t) {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ t.printStackTrace(writer);
+ return stringWriter.toString();
+
+ }
+
+
+
+ @Override
+ public void run(TestResult result) {
+ for (Iterator e= tests(); e.hasNext(); ) {
+ if (result.shouldStop() ){
+ break;
+ }
+ Test test= (Test)e.next();
+ test.run(result);
+ }
+
+ }
+
+ public int countTestCases() {
+ int count= 0;
+
+ for (Iterator e= tests(); e.hasNext(); ) {
+ Test test= e.next();
+ count= count + test.countTestCases();
+ }
+ return count;
+ }
+ public Iterator tests() {
+ return tests.iterator();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/runner/BaseTestRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/runner/BaseTestRunner.java
new file mode 100644
index 0000000000..b6ff184b69
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/runner/BaseTestRunner.java
@@ -0,0 +1,85 @@
+package org.litejunit.v2.runner;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.text.NumberFormat;
+
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestListener;
+import org.litejunit.v2.TestSuite;
+
+
+public abstract class BaseTestRunner implements TestListener {
+ public static final String SUITE_METHODNAME= "suite";
+ /**
+ * Returns a filtered stack trace
+ */
+ public static String getFilteredTrace(Throwable t) {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ t.printStackTrace(writer);
+ StringBuffer buffer= stringWriter.getBuffer();
+ String trace= buffer.toString();
+ return trace;
+ //return BaseTestRunner.filterStack(trace);
+ }
+
+ public Test getTest(String suiteClassName) {
+ if (suiteClassName.length() <= 0) {
+ return null;
+ }
+ Class testClass= null;
+ try {
+ testClass= loadSuiteClass(suiteClassName);
+ } catch (ClassNotFoundException e) {
+ String clazz= e.getMessage();
+ if (clazz == null)
+ clazz= suiteClassName;
+ runFailed("Class not found \""+clazz+"\"");
+ return null;
+ } catch(Exception e) {
+ runFailed("Error: "+e.toString());
+ return null;
+ }
+ Method suiteMethod= null;
+ try {
+ suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
+ } catch(Exception e) {
+ // try to extract a test suite automatically
+ //clearStatus();
+ return new TestSuite(testClass);
+ }
+ Test test= null;
+ try {
+ test= (Test)suiteMethod.invoke(null, new Class[0]); // static method
+ if (test == null)
+ return test;
+ }
+ catch (InvocationTargetException e) {
+ runFailed("Failed to invoke suite():" + e.getTargetException().toString());
+ return null;
+ }
+ catch (IllegalAccessException e) {
+ runFailed("Failed to invoke suite():" + e.toString());
+ return null;
+ }
+
+ //clearStatus();
+ return test;
+ }
+ protected Class> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+
+ //TODO
+ return Class.forName(suiteClassName);
+
+
+ //return getLoader().load(suiteClassName);
+ }
+ protected abstract void runFailed(String message);
+
+ public String elapsedTimeAsString(long runTime) {
+ return NumberFormat.getInstance().format((double)runTime/1000);
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/textui/TestRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/textui/TestRunner.java
new file mode 100644
index 0000000000..0ffab6b747
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v2/textui/TestRunner.java
@@ -0,0 +1,202 @@
+package org.litejunit.v2.textui;
+
+
+import java.lang.reflect.*;
+import java.text.NumberFormat;
+import java.util.*;
+
+import org.litejunit.v2.AssertionFailedError;
+import org.litejunit.v2.Test;
+import org.litejunit.v2.TestFailure;
+import org.litejunit.v2.TestResult;
+import org.litejunit.v2.TestSuite;
+import org.litejunit.v2.runner.BaseTestRunner;
+
+import java.io.PrintStream;
+
+
+public class TestRunner extends BaseTestRunner {
+ PrintStream writer= System.out;
+ int column= 0;
+
+ /**
+ * Constructs a TestRunner.
+ */
+ public TestRunner() {
+ }
+
+
+ /**
+ * Always use the StandardTestSuiteLoader. Overridden from
+ * BaseTestRunner.
+ */
+ /*public TestSuiteLoader getLoader() {
+ return new StandardTestSuiteLoader();
+ }*/
+
+ public synchronized void addError(Test test, Throwable t) {
+ writer().print("E");
+ }
+
+ public synchronized void addFailure(Test test, AssertionFailedError t) {
+ writer().print("F");
+ }
+
+
+
+ public TestResult doRun(Test suite) {
+ TestResult result= new TestResult();
+ result.addListener(this);
+ long startTime= System.currentTimeMillis();
+ suite.run(result);
+ long endTime= System.currentTimeMillis();
+ long runTime= endTime-startTime;
+ writer().println();
+ writer().println("Time: "+elapsedTimeAsString(runTime));
+ print(result);
+
+ writer().println();
+
+
+ return result;
+ }
+
+
+
+ public synchronized void startTest(Test test) {
+ writer().print(".");
+ if (column++ >= 40) {
+ writer().println();
+ column= 0;
+ }
+ }
+
+ public void endTest(Test test) {
+ }
+
+ public static void main(String args[]) {
+ TestRunner testRunner= new TestRunner();
+ try {
+ TestResult r= testRunner.start(args);
+ if (!r.wasSuccessful())
+ System.exit(-1);
+ System.exit(0);
+ } catch(Exception e) {
+ System.err.println(e.getMessage());
+ System.exit(-2);
+ }
+ }
+ /**
+ * Prints failures to the standard output
+ */
+ public synchronized void print(TestResult result) {
+ printErrors(result);
+ printFailures(result);
+ printHeader(result);
+ }
+ /**
+ * Prints the errors to the standard output
+ */
+ public void printErrors(TestResult result) {
+ if (result.errorCount() != 0) {
+ if (result.errorCount() == 1)
+ writer().println("There was "+result.errorCount()+" error:");
+ else
+ writer().println("There were "+result.errorCount()+" errors:");
+
+ int i= 1;
+ for (Iterator e= result.errors(); e.hasNext(); i++) {
+ TestFailure failure= e.next();
+ writer().println(i+") "+failure.failedTest());
+ writer().print(getFilteredTrace(failure.thrownException()));
+ }
+ }
+ }
+ /**
+ * Prints failures to the standard output
+ */
+ public void printFailures(TestResult result) {
+ if (result.failureCount() != 0) {
+ if (result.failureCount() == 1)
+ writer().println("There was " + result.failureCount() + " failure:");
+ else
+ writer().println("There were " + result.failureCount() + " failures:");
+ int i = 1;
+ for (Iterator e= result.failures(); e.hasNext(); i++) {
+ TestFailure failure= (TestFailure) e.next();
+ writer().print(i + ") " + failure.failedTest());
+ Throwable t= failure.thrownException();
+ writer().print(getFilteredTrace(failure.thrownException()));
+ }
+ }
+ }
+ /**
+ * Prints the header of the report
+ */
+ public void printHeader(TestResult result) {
+ if (result.wasSuccessful()) {
+ writer().println();
+ writer().print("OK");
+ writer().println (" (" + result.runCount() + " tests)");
+
+ } else {
+ writer().println();
+ writer().println("FAILURES!!!");
+ writer().println("Tests run: "+result.runCount()+
+ ", Failures: "+result.failureCount()+
+ ", Errors: "+result.errorCount());
+ }
+ }
+
+
+ /**
+ * Starts a test run. Analyzes the command line arguments
+ * and runs the given test suite.
+ */
+ protected TestResult start(String args[]) throws Exception {
+ if(args.length == 0){
+ throw new Exception("Usage: TestRunner testCaseName");
+ }
+ String testCase= args[0];
+
+ try {
+ Test suite= getTest(testCase);
+ return doRun(suite);
+ }
+ catch(Exception e) {
+ throw new Exception("Could not create and run test suite: "+e);
+ }
+ }
+
+ protected void runFailed(String message) {
+ System.err.println(message);
+ System.exit(-1);
+ }
+
+ /**
+ * Runs a suite extracted from a TestCase subclass.
+ */
+ static public void run(Class testClass) {
+ run(new TestSuite(testClass));
+ }
+ /**
+ * Runs a single test and collects its results.
+ * This method can be used to start a test run
+ * from your program.
+ *
+ * public static void main (String[] args) {
+ * test.textui.TestRunner.run(suite());
+ * }
+ *
+ */
+ static public void run(Test suite) {
+ TestRunner aTestRunner= new TestRunner();
+ aTestRunner.doRun(suite);
+ }
+
+ protected PrintStream writer() {
+ return writer;
+ }
+
+
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/After.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/After.java
new file mode 100644
index 0000000000..f27496b8e1
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/After.java
@@ -0,0 +1,12 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface After {
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/AfterClass.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/AfterClass.java
new file mode 100644
index 0000000000..82618d7afc
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/AfterClass.java
@@ -0,0 +1,13 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface AfterClass {
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Assert.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Assert.java
new file mode 100644
index 0000000000..6d1b7689f9
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Assert.java
@@ -0,0 +1,269 @@
+package org.litejunit.v3;
+
+/**
+ * A set of assertion methods useful for writing tests. Only failed assertions are recorded.
+ * These methods can be used directly: Assert.assertEquals(...), however, they
+ * read better if they are referenced through static import:
+ *
+ * import static org.junit.Assert.*;
+ * ...
+ * assertEquals(...);
+ *
+ */
+
+public class Assert {
+ /**
+ * Protect constructor since it is a static only class
+ */
+ protected Assert() {
+ }
+
+ /**
+ * Asserts that a condition is true. If it isn't it throws an
+ * AssertionError with the given message.
+ */
+ static public void assertTrue(String message, boolean condition) {
+ if (!condition)
+ fail(message);
+ }
+
+ /**
+ * Asserts that a condition is true. If it isn't it throws an
+ * AssertionError.
+ */
+ static public void assertTrue(boolean condition) {
+ assertTrue(null, condition);
+ }
+
+ /**
+ * Asserts that a condition is false. If it isn't it throws an
+ * AssertionError with the given message.
+ */
+ static public void assertFalse(String message, boolean condition) {
+ assertTrue(message, !condition);
+ }
+
+ /**
+ * Asserts that a condition is false. If it isn't it throws an
+ * AssertionError.
+ */
+ static public void assertFalse(boolean condition) {
+ assertFalse(null, condition);
+ }
+
+ /**
+ * Fails a test with the given message.
+ */
+ static public void fail(String message) {
+ throw new AssertionError(message);
+ }
+
+ /**
+ * Fails a test with no message.
+ */
+ static public void fail() {
+ fail(null);
+ }
+
+ /**
+ * Asserts that two objects are equal. If they are not, an
+ * AssertionError is thrown with the given message.
+ */
+ static public void assertEquals(String message, Object expected, Object actual) {
+ if (expected == null && actual == null)
+ return;
+ if (expected != null && expected.equals(actual))
+ return;
+ if (expected instanceof String && actual instanceof String)
+ throw new ComparisonFailure(message, (String)expected, (String)actual);
+ else
+ failNotEquals(message, expected, actual);
+ }
+
+ /**
+ * Asserts that two objects are equal. If they are not, an
+ * AssertionError is thrown.
+ */
+ static public void assertEquals(Object expected, Object actual) {
+ assertEquals(null, expected, actual);
+ }
+
+ /**
+ * Asserts that two object arrays are equal. If they are not, an
+ * AssertionError is thrown with the given message.
+ */
+ public static void assertEquals(String message, Object[] expecteds, Object[] actuals) {
+ if (expecteds == actuals)
+ return;
+ String header = message == null ? "" : message + ": ";
+ if (expecteds == null)
+ fail(header + "expected array was null");
+ if (actuals == null)
+ fail(header + "actual array was null");
+ if (actuals.length != expecteds.length)
+ fail(header + "array lengths differed, expected.length=" + expecteds.length + " actual.length=" + actuals.length);
+
+ for (int i= 0; i < expecteds.length; i++) {
+ Object o1= expecteds[i];
+ Object o2= actuals[i];
+ if (o1.getClass().isArray() && o2.getClass().isArray()) {
+ Object[] expected= (Object[]) o1;
+ Object[] actual= (Object[]) o2;
+ assertEquals(header + "arrays first differed at element " + i + ";", expected, actual);
+ } else
+ assertEquals(header + "arrays first differed at element [" + i + "];", o1, o2);
+ }
+ }
+
+ /**
+ * Asserts that two object arrays are equal. If they are not, an
+ * AssertionError is thrown.
+ */
+ public static void assertEquals(Object[] expecteds, Object[] actuals) {
+ assertEquals(null, expecteds, actuals);
+ }
+
+ /**
+ * Asserts that two doubles are equal to within a positive delta. If they
+ * are not, an AssertionError is thrown with the given message. If the
+ * expected value is infinity then the delta value is ignored. NaNs are
+ * considered equal:
+ * assertEquals(Double.NaN, Double.NaN, *) passes
+ */
+ static public void assertEquals(String message, double expected, double actual, double delta) {
+ if (Double.compare(expected, actual) == 0)
+ return;
+ if (!(Math.abs(expected - actual) <= delta))
+ failNotEquals(message, new Double(expected), new Double(actual));
+ }
+
+ /**
+ * Asserts that two doubles are equal to within a positive delta. If they
+ * are not, an AssertionError is thrown. If the
+ * expected value is infinity then the delta value is ignored.NaNs are
+ * considered equal:
+ * assertEquals(Double.NaN, Double.NaN, *) passes
+ */
+ static public void assertEquals(double expected, double actual, double delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+
+ /**
+ * Asserts that two floats are equal to within a positive delta. If they
+ * are not, an AssertionError is thrown with the given message. If the
+ * expected value is infinity then the delta value is ignored.NaNs are
+ * considered equal:
+ * assertEquals(Float.NaN, Float.NaN, *) passes
+ */
+ static public void assertEquals(String message, float expected, float actual, float delta) {
+ if (Float.compare(expected, actual) == 0)
+ return;
+ if (!(Math.abs(expected - actual) <= delta))
+ failNotEquals(message, new Float(expected), new Float(actual));
+ }
+
+ /**
+ * Asserts that two floats are equal to within a positive delta. If they
+ * are not, an AssertionError is thrown. If the
+ * expected value is infinity then the delta value is ignored.NaNs are
+ * considered equal:
+ * assertEquals(Float.NaN, Float.NaN, *) passes
+ */
+ static public void assertEquals(float expected, float actual, float delta) {
+ assertEquals(null, expected, actual, delta);
+ }
+
+ /**
+ * Asserts that an object isn't null. If it is an AssertionError is
+ * thrown with the given message.
+ */
+ static public void assertNotNull(String message, Object object) {
+ assertTrue(message, object != null);
+ }
+
+ /**
+ * Asserts that an object isn't null. If it is an AssertionError is
+ * thrown.
+ */
+ static public void assertNotNull(Object object) {
+ assertNotNull(null, object);
+ }
+
+ /**
+ * Asserts that an object is null. If it is not, an AssertionError is
+ * thrown with the given message.
+ */
+ static public void assertNull(String message, Object object) {
+ assertTrue(message, object == null);
+ }
+
+ /**
+ * Asserts that an object is null. If it isn't an AssertionError is
+ * thrown.
+ */
+ static public void assertNull(Object object) {
+ assertNull(null, object);
+ }
+
+ /**
+ * Asserts that two objects refer to the same object. If they are not, an
+ * AssertionError is thrown with the given message.
+ */
+ static public void assertSame(String message, Object expected, Object actual) {
+ if (expected == actual)
+ return;
+ failNotSame(message, expected, actual);
+ }
+
+ /**
+ * Asserts that two objects refer to the same object. If they are not the
+ * same, an AssertionError is thrown.
+ */
+ static public void assertSame(Object expected, Object actual) {
+ assertSame(null, expected, actual);
+ }
+
+ /**
+ * Asserts that two objects do not refer to the same object. If they do
+ * refer to the same object, an AssertionError is thrown with the given
+ * message.
+ */
+ static public void assertNotSame(String message, Object expected, Object actual) {
+ if (expected == actual)
+ failSame(message);
+ }
+
+ /**
+ * Asserts that two objects do not refer to the same object. If they do
+ * refer to the same object, an AssertionError is thrown.
+ */
+ static public void assertNotSame(Object expected, Object actual) {
+ assertNotSame(null, expected, actual);
+ }
+
+ static private void failSame(String message) {
+ String formatted= "";
+ if (message != null)
+ formatted= message + " ";
+ fail(formatted + "expected not same");
+ }
+
+ static private void failNotSame(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message + " ";
+ fail(formatted + "expected same:<" + expected + "> was not:<" + actual + ">");
+ }
+
+ static private void failNotEquals(String message, Object expected, Object actual) {
+ fail(format(message, expected, actual));
+ }
+
+ static String format(String message, Object expected, Object actual) {
+ String formatted= "";
+ if (message != null)
+ formatted= message + " ";
+ return formatted + "expected:<" + expected + "> but was:<" + actual + ">";
+ }
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Before.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Before.java
new file mode 100644
index 0000000000..72e0e3beb2
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Before.java
@@ -0,0 +1,13 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Before {
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/BeforeClass.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/BeforeClass.java
new file mode 100644
index 0000000000..6334ab45b2
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/BeforeClass.java
@@ -0,0 +1,11 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface BeforeClass {
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/ComparisonFailure.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/ComparisonFailure.java
new file mode 100644
index 0000000000..77f9ea6f5f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/ComparisonFailure.java
@@ -0,0 +1,124 @@
+package org.litejunit.v3;
+
+/**
+ * Thrown when an assertEquals(String, String) fails. Create and throw
+ * a ComparisonFailure manually if you want to show users the difference between two complex
+ * strings.
+ *
+ * Inspired by a patch from Alex Chaffee (alex@purpletech.com)
+ */
+public class ComparisonFailure extends AssertionError {
+ private static final int MAX_CONTEXT_LENGTH= 20;
+ private static final long serialVersionUID= 1L;
+
+ private String fExpected;
+ private String fActual;
+
+ /**
+ * Constructs a comparison failure.
+ * @param message the identifying message or null
+ * @param expected the expected string value
+ * @param actual the actual string value
+ */
+ public ComparisonFailure (String message, String expected, String actual) {
+ super (message);
+ fExpected= expected;
+ fActual= actual;
+ }
+
+ /**
+ * Returns "..." in place of common prefix and "..." in
+ * place of common suffix between expected and actual.
+ *
+ * @see java.lang.Throwable#getMessage()
+ */
+ @Override
+ public String getMessage() {
+ return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
+ }
+
+ /**
+ * Returns the actual value
+ * @return the actual string value
+ */
+ public String getActual() {
+ return fActual;
+ }
+ /**
+ * Returns the expected value
+ * @return the expected string value
+ */
+ public String getExpected() {
+ return fExpected;
+ }
+
+ private static class ComparisonCompactor {
+ private static final String ELLIPSIS= "...";
+ private static final String DELTA_END= "]";
+ private static final String DELTA_START= "[";
+
+ private int fContextLength;
+ private String fExpected;
+ private String fActual;
+ private int fPrefix;
+ private int fSuffix;
+
+ public ComparisonCompactor(int contextLength, String expected, String actual) {
+ fContextLength= contextLength;
+ fExpected= expected;
+ fActual= actual;
+ }
+
+ public String compact(String message) {
+ if (fExpected == null || fActual == null || areStringsEqual())
+ return Assert.format(message, fExpected, fActual);
+
+ findCommonPrefix();
+ findCommonSuffix();
+ String expected= compactString(fExpected);
+ String actual= compactString(fActual);
+ return Assert.format(message, expected, actual);
+ }
+
+ private String compactString(String source) {
+ String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
+ if (fPrefix > 0)
+ result= computeCommonPrefix() + result;
+ if (fSuffix > 0)
+ result= result + computeCommonSuffix();
+ return result;
+ }
+
+ private void findCommonPrefix() {
+ fPrefix= 0;
+ int end= Math.min(fExpected.length(), fActual.length());
+ for (; fPrefix < end; fPrefix++) {
+ if (fExpected.charAt(fPrefix) != fActual.charAt(fPrefix))
+ break;
+ }
+ }
+
+ private void findCommonSuffix() {
+ int expectedSuffix= fExpected.length() - 1;
+ int actualSuffix= fActual.length() - 1;
+ for (; actualSuffix >= fPrefix && expectedSuffix >= fPrefix; actualSuffix--, expectedSuffix--) {
+ if (fExpected.charAt(expectedSuffix) != fActual.charAt(actualSuffix))
+ break;
+ }
+ fSuffix= fExpected.length() - expectedSuffix;
+ }
+
+ private String computeCommonPrefix() {
+ return (fPrefix > fContextLength ? ELLIPSIS : "") + fExpected.substring(Math.max(0, fPrefix - fContextLength), fPrefix);
+ }
+
+ private String computeCommonSuffix() {
+ int end= Math.min(fExpected.length() - fSuffix + 1 + fContextLength, fExpected.length());
+ return fExpected.substring(fExpected.length() - fSuffix + 1, end) + (fExpected.length() - fSuffix + 1 < fExpected.length() - fContextLength ? ELLIPSIS : "");
+ }
+
+ private boolean areStringsEqual() {
+ return fExpected.equals(fActual);
+ }
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Ignore.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Ignore.java
new file mode 100644
index 0000000000..1652ac2431
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Ignore.java
@@ -0,0 +1,31 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Sometimes you want to temporarily disable a test. Methods annotated with @Test
+ * that are also annotated with @Ignore will not be executed as tests. Native JUnit 4 test runners
+ * should report the number of ignored tests along with the number of tests that ran and the
+ * number of tests that failed.
+ *
+ * For example:
+ *
+ * @Ignore @Test public void something() { ...
+ *
+ * @Ignore takes an optional default parameter if you want to record why a test is being ignored:
+ *
+ * @Ignore("not ready yet") @Test public void something() { ...
+ *
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Ignore {
+ /**
+ * The optional reason why the test is ignored.
+ */
+ String value() default "";
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Test.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Test.java
new file mode 100644
index 0000000000..f390d10671
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/Test.java
@@ -0,0 +1,62 @@
+package org.litejunit.v3;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The Test annotation tells JUnit that the public void method
+ * to which it is attached can be run as a test case. To run the method,
+ * JUnit first constructs a fresh instance of the class then invokes the
+ * annotated method. Any exceptions thrown by the test will be reported
+ * by JUnit as a failure. If no exceptions are thrown, the test is assumed
+ * to have succeeded.
+ *
+ * A simple test looks like this:
+ *
+ * public class Example {
+ * @Test public void method() {
+ * System.out.println("Hello");
+ * }
+ * }
+ *
+ *
+ * The Test annotation supports two optional parameters.
+ * The first, expected, declares that a test method should throw
+ * an exception. If it doesn't throw an exception or if it throws a different exception
+ * than the one declared, the test fails. For example, the following test succeeds:
+ *
+ * @Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
+ * new ArrayList<Object>().get(1);
+ * }
+ *
+ *
+ * The second optional parameter, timeout, causes a test to fail if it takes longer than a specified
+ * amount of clock time (measured in milliseconds). The following test fails:
+ *
+ * @Test(timeout=100) public void infinity() {
+ * for(;;);
+ * }
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Test {
+ static class None extends Throwable {
+ private static final long serialVersionUID= 1L;
+ private None() {
+ }
+ }
+
+ /**
+ * Optionally specify expected, a Throwable, to cause a test method to succeed iff
+ * an exception of the specified class is thrown by the method.
+ */
+ Class extends Throwable> expected() default None.class;
+
+ /**
+ * Optionally specify timeout in milliseconds to cause a test method to fail if it
+ * takes longer than that number of milliseconds.*/
+ long timeout() default 0L;
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/Failure.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/Failure.java
new file mode 100644
index 0000000000..2eb516b75f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/Failure.java
@@ -0,0 +1,78 @@
+package org.litejunit.v3.notification;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.litejunit.v3.runner.Description;
+
+
+/**
+ * A Failure holds a description of the failed test and the
+ * exception that was thrown while running it. In most cases the Description
+ * will be of a single test. However, if problems are encountered while constructing the
+ * test (for example, if a @BeforeClass method is not static), it may describe
+ * something other than a single test.
+ */
+public class Failure {
+ private final Description fDescription;
+ private Throwable fThrownException;
+
+ /**
+ * Constructs a Failure with the given description and exception.
+ * @param description a Description of the test that failed
+ * @param thrownException the exception that was thrown while running the test
+ */
+ public Failure(Description description, Throwable thrownException) {
+ fThrownException = thrownException;
+ fDescription= description;
+ }
+
+ /**
+ * @return a user-understandable label for the test
+ */
+ public String getTestHeader() {
+ return fDescription.getDisplayName();
+ }
+
+ /**
+ * @return the raw description of the context of the failure.
+ */
+ public Description getDescription() {
+ return fDescription;
+ }
+
+ /**
+ * @return the exception thrown
+ */
+
+ public Throwable getException() {
+ return fThrownException;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer= new StringBuffer();
+ buffer.append(getTestHeader() + ": "+fThrownException.getMessage());
+ return buffer.toString();
+ }
+
+ /**
+ * Convenience method
+ * @return the printed form of the exception
+ */
+ public String getTrace() {
+ StringWriter stringWriter= new StringWriter();
+ PrintWriter writer= new PrintWriter(stringWriter);
+ getException().printStackTrace(writer);
+ StringBuffer buffer= stringWriter.getBuffer();
+ return buffer.toString();
+ }
+
+ /**
+ * Convenience method
+ * @return the message of the thrown exception
+ */
+ public String getMessage() {
+ return getException().getMessage();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunListener.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunListener.java
new file mode 100644
index 0000000000..aa30aa9abf
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunListener.java
@@ -0,0 +1,53 @@
+package org.litejunit.v3.notification;
+
+import org.litejunit.v3.runner.Description;
+import org.litejunit.v3.runner.Result;
+
+
+public class RunListener {
+
+ /**
+ * Called before any tests have been run.
+ * @param description describes the tests to be run
+ */
+ public void testRunStarted(Description description) throws Exception {
+ }
+
+ /**
+ * Called when all tests have finished
+ * @param result the summary of the test run, including all the tests that failed
+ */
+ public void testRunFinished(Result result) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test is about to be started.
+ * @param description the description of the test that is about to be run (generally a class and method name)
+ */
+ public void testStarted(Description description) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test has finished, whether the test succeeds or fails.
+ * @param description the description of the test that just ran
+ */
+ public void testFinished(Description description) throws Exception {
+ }
+
+ /**
+ * Called when an atomic test fails.
+ * @param failure describes the test that failed and the exception that was thrown
+ */
+ public void testFailure(Failure failure) throws Exception {
+ }
+
+ /**
+ * Called when a test will not be run, generally because a test method is annotated with @Ignored.
+ * @param description describes the test that will not be run
+ */
+ public void testIgnored(Description description) throws Exception {
+ }
+
+}
+
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunNotifier.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunNotifier.java
new file mode 100644
index 0000000000..d7d16e0677
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/RunNotifier.java
@@ -0,0 +1,139 @@
+package org.litejunit.v3.notification;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.litejunit.v3.runner.Description;
+import org.litejunit.v3.runner.Result;
+
+
+
+/**
+ * If you write custom runners, you may need to notify JUnit of your progress running tests.
+ * Do this by invoking the RunNotifier passed to your implementation of
+ * Runner.run(RunNotifier notifier). Future evolution of this class is likely to
+ * move fireTestRunStarted() and fireTestRunFinished()
+ * to a separate class since they should only be called once per run.
+ */
+public class RunNotifier {
+ private List fListeners= new ArrayList();
+ private boolean fPleaseStop= false;
+
+ /** Internal use only
+ */
+ public void addListener(RunListener listener) {
+ fListeners.add(listener);
+ }
+
+ /** Internal use only
+ */
+ public void removeListener(RunListener listener) {
+ fListeners.remove(listener);
+ }
+
+ private abstract class SafeNotifier {
+ void run() {
+ for (Iterator all= fListeners.iterator(); all.hasNext();) {
+ try {
+ notifyListener(all.next());
+ } catch (Exception e) {
+ all.remove(); // Remove the offending listener first to avoid an infinite loop
+ fireTestFailure(new Failure(Description.TEST_MECHANISM, e));
+ }
+ }
+ }
+
+ abstract protected void notifyListener(RunListener each) throws Exception;
+ }
+
+ /**
+ * Do not invoke.
+ */
+ public void fireTestRunStarted(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testRunStarted(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Do not invoke.
+ */
+ public void fireTestRunFinished(final Result result) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testRunFinished(result);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test is about to start.
+ * @param description the description of the atomic test (generally a class and method name)
+ * @throws StoppedByUserException thrown if a user has requested that the test run stop
+ */
+ public void fireTestStarted(final Description description) throws StoppedByUserException {
+ if (fPleaseStop)
+ throw new StoppedByUserException();
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testStarted(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test failed.
+ * @param failure the description of the test that failed and the exception thrown
+ */
+ public void fireTestFailure(final Failure failure) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testFailure(failure);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test was ignored.
+ * @param description the description of the ignored test
+ */
+ public void fireTestIgnored(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testIgnored(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Invoke to tell listeners that an atomic test finished. Always invoke fireTestFinished()
+ * if you invoke fireTestStarted() as listeners are likely to expect them to come in pairs.
+ * @param description the description of the test that finished
+ */
+ public void fireTestFinished(final Description description) {
+ new SafeNotifier() {
+ @Override
+ protected void notifyListener(RunListener each) throws Exception {
+ each.testFinished(description);
+ };
+ }.run();
+ }
+
+ /**
+ * Ask that the tests run stop before starting the next test. Phrased politely because
+ * the test currently running will not be interrupted. It seems a little odd to put this
+ * functionality here, but the RunNotifier is the only object guaranteed
+ * to be shared amongst the many runners involved.
+ */
+ public void pleaseStop() {
+ fPleaseStop= true;
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/StoppedByUserException.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/StoppedByUserException.java
new file mode 100644
index 0000000000..829462445c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/notification/StoppedByUserException.java
@@ -0,0 +1,11 @@
+package org.litejunit.v3.notification;
+
+/**
+ * Thrown when a user has requested that the test run stop. Writers of
+ * test running GUIs should be prepared to catch a StoppedByUserException.
+ *
+ * @see org.junit.runner.notification.RunNotifier
+ */
+public class StoppedByUserException extends RuntimeException {
+ private static final long serialVersionUID= 1L;
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/requests/ClassRequest.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/requests/ClassRequest.java
new file mode 100644
index 0000000000..315bbb6482
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/requests/ClassRequest.java
@@ -0,0 +1,48 @@
+/**
+ *
+ */
+package org.litejunit.v3.requests;
+
+import java.lang.reflect.Constructor;
+
+import org.litejunit.v3.runner.Request;
+import org.litejunit.v3.runner.Runner;
+import org.litejunit.v3.runners.TestClassRunner;
+
+
+public class ClassRequest extends Request {
+ private final Class> fTestClass;
+
+ public ClassRequest(Class> each) {
+ fTestClass= each;
+ }
+
+ @Override
+ public Runner getRunner() {
+ Class runnerClass= getRunnerClass(fTestClass);
+ try {
+ Constructor constructor= runnerClass.getConstructor(Class.class); // TODO good error message if no such constructor
+ Runner runner= (Runner) constructor
+ .newInstance(new Object[] { fTestClass });
+ return runner;
+ } catch (Exception e) {
+ return null;
+ //return Request.errorReport(fTestClass, e).getRunner();
+ }
+ }
+
+ Class getRunnerClass(Class> testClass) {
+ /*RunWith annotation= testClass.getAnnotation(RunWith.class);
+ if (annotation != null) {
+ return annotation.value();
+ } else if (isPre4Test(testClass)) {
+ return OldTestClassRunner.class;
+ } else {*/
+ return TestClassRunner.class;
+ /*}*/
+ }
+
+ /*boolean isPre4Test(Class> testClass) {
+ return junit.framework.TestCase.class.isAssignableFrom(testClass);
+ }*/
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Description.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Description.java
new file mode 100644
index 0000000000..db3610fd3f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Description.java
@@ -0,0 +1,127 @@
+package org.litejunit.v3.runner;
+
+import java.util.ArrayList;
+
+/**
+ * A Description describes a test which is to be run or has been run. Descriptions can
+ * be atomic (a single test) or compound (containing children tests). Descriptions are used
+ * to provide feedback about the tests that are about to run (for example, the tree view
+ * visible in many IDEs) or tests that have been run (for example, the failures view).
+ * Descriptions are implemented as a single class rather than a Composite because
+ * they are entirely informational. They contain no logic aside from counting their tests.
+ * In the past, we used the raw junit.framework.TestCases and junit.framework.TestSuites
+ * to display the tree of tests. This was no longer viable in JUnit 4 because atomic tests no longer have a superclass below Object.
+ * We needed a way to pass a class and name together. Description emerged from this.
+ *
+ * @see org.junit.runner.Request
+ * @see org.junit.runner.Runner
+ */
+public class Description {
+
+ /**
+ * Create a Description named name.
+ * Generally, you will add children to this Description.
+ * @param name The name of the Description
+ * @return A Description named name
+ */
+ public static Description createSuiteDescription(String name) {
+ return new Description(name);
+ }
+
+ /**
+ * Create a Description of a single test named name in the class clazz.
+ * Generally, this will be a leaf Description.
+ * @param clazz The class of the test
+ * @param name The name of the test (a method name for test annotated with @Test)
+ * @return A Description named name
+ */
+ public static Description createTestDescription(Class clazz, String name) {
+ return new Description(String.format("%s(%s)", name, clazz.getName()));
+ }
+
+ /**
+ * Create a generic Description that says there are tests in testClass.
+ * This is used as a last resort when you cannot precisely describe the individual tests in the class.
+ * @param testClass A Class containing tests
+ * @return A Description of testClass
+ */
+ public static Description createSuiteDescription(Class> testClass) {
+ return new Description(testClass.getName());
+ }
+
+ public static Description TEST_MECHANISM = new Description("Test mechanism");
+ private final ArrayList fChildren= new ArrayList();
+ private final String fDisplayName;
+
+ //TODO we seem to be using the static factories exclusively
+ private Description(final String displayName) {
+ fDisplayName= displayName;
+ }
+
+ /**
+ * @return a user-understandable label
+ */
+ public String getDisplayName() {
+ return fDisplayName;
+ }
+
+ /**
+ * Add description as a child of the receiver.
+ * @param description The soon-to-be child.
+ */
+ public void addChild(Description description) {
+ getChildren().add(description);
+ }
+
+ /**
+ * @return the receiver's children, if any
+ */
+ public ArrayList getChildren() {
+ return fChildren;
+ }
+
+ /**
+ * @return true if the receiver is a suite
+ */
+ public boolean isSuite() {
+ return !isTest();
+ }
+
+ /**
+ * @return true if the receiver is an atomic test
+ */
+ public boolean isTest() {
+ return getChildren().isEmpty();
+ }
+
+ /**
+ * @return the total number of atomic tests in the receiver
+ */
+ public int testCount() {
+ if (isTest())
+ return 1;
+ int result= 0;
+ for (Description child : getChildren())
+ result+= child.testCount();
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return getDisplayName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Description))
+ return false;
+ Description d = (Description) obj;
+ return getDisplayName().equals(d.getDisplayName())
+ && getChildren().equals(d.getChildren());
+ }
+
+ @Override
+ public String toString() {
+ return getDisplayName();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/JUnitCore.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/JUnitCore.java
new file mode 100644
index 0000000000..662f5ffd0c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/JUnitCore.java
@@ -0,0 +1,167 @@
+package org.litejunit.v3.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.litejunit.v3.notification.RunListener;
+import org.litejunit.v3.notification.RunNotifier;
+import org.litejunit.v3.runners.InitializationError;
+import org.litejunit.v3.runners.TestClassRunner;
+import org.litejunit.v3.runners.TextListener;
+
+
+
+/**
+ * JUnitCore is a facade for running tests. It supports running JUnit 4 tests,
+ * JUnit 3.8.2 tests, and mixtures. To run tests from the command line, run java org.junit.runner.JUnitCore TestClass1 TestClass2 ....
+ * For one-shot test runs, use the static method runClasses(Class... classes)
+ * . If you want to add special listeners,
+ * create an instance of JUnitCore first and use it to run the tests.
+ *
+ * @see org.junit.runner.Result
+ * @see org.junit.runner.notification.RunListener
+ * @see org.junit.runner.Request
+ */
+public class JUnitCore {
+
+ private RunNotifier notifier;
+
+ /**
+ * Create a new JUnitCore to run tests.
+ */
+ public JUnitCore() {
+ notifier= new RunNotifier();
+ }
+
+ /**
+ * Run the tests contained in the classes named in the args.
+ * If all tests run successfully, exit with a status of 0. Otherwise exit with a status of 1.
+ * Write feedback while tests are running and write
+ * stack traces for all failed tests after the tests all complete.
+ * @param args names of classes in which to find tests to run
+ */
+ /*public static void main(String... args) {
+ Class> clz = null;
+ try {
+ clz = Class.forName(args[0]);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ Request request = Request.aClass(clz);
+
+ new JUnitCore().run(request);
+
+ Result result= new JUnitCore().runMain(args);
+ killAllThreads(result);
+ }*/
+ public static void runClass(Class> clz){
+ try {
+ TestClassRunner runner = new TestClassRunner(clz);
+ JUnitCore core = new JUnitCore();
+ core.addListener(new TextListener());
+ Result result = core.run(runner);
+
+ } catch (InitializationError e) {
+
+ e.printStackTrace();
+ }
+
+ }
+ /*private static void killAllThreads(Result result) {
+ System.exit(result.wasSuccessful() ? 0 : 1);
+ }*/
+
+ /**
+ * Run the tests contained in classes. Write feedback while the tests
+ * are running and write stack traces for all failed tests after all tests complete. This is
+ * similar to main(), but intended to be used programmatically.
+ * @param classes Classes in which to find tests
+ * @return a Result describing the details of the test run and the failed tests.
+ */
+ /*public static Result runClasses(Class... classes) {
+ return new JUnitCore().run(classes);
+ }*/
+
+ /**
+ * Do not use. Testing purposes only.
+ */
+ /*public Result runMain(String... args) {
+
+ List classes= new ArrayList();
+ for (String each : args)
+ try {
+ classes.add(Class.forName(each));
+ } catch (ClassNotFoundException e) {
+ System.out.println("Could not find class: " + each);
+ }
+ RunListener listener= new TextListener();
+ addListener(listener);
+ return run(classes.toArray(new Class[0]));
+ }*/
+
+
+
+ /**
+ * Run all the tests in classes.
+ * @param classes the classes containing tests
+ * @return a Result describing the details of the test run and the failed tests.
+ */
+ /*public Result run(Class... classes) {
+ return run(Request.classes("All", classes));
+ }*/
+
+ /**
+ * Run all the tests contained in request.
+ * @param request the request describing tests
+ * @return a Result describing the details of the test run and the failed tests.
+ */
+ /*public Result run(Request request) {
+ return run(request.getRunner());
+ }*/
+
+ /**
+ * Run all the tests contained in JUnit 3.8.x test. Here for backward compatibility.
+ * @param test the old-style test
+ * @return a Result describing the details of the test run and the failed tests.
+ */
+ /*public Result run(junit.framework.Test test) {
+ return run(new OldTestClassRunner(test));
+ }
+ */
+ /**
+ * Do not use. Testing purposes only.
+ */
+ public Result run(Runner runner) {
+ Result result= new Result();
+ RunListener listener= result.createListener();
+ addListener(listener);
+
+ try {
+ notifier.fireTestRunStarted(runner.getDescription());
+ runner.run(notifier);
+ notifier.fireTestRunFinished(result);
+ } finally {
+ removeListener(listener);
+ }
+ return result;
+ }
+
+ /**
+ * Add a listener to be notified as the tests run.
+ * @param listener the listener
+ * @see org.junit.runner.notification.RunListener
+ */
+ public void addListener(RunListener listener) {
+ notifier.addListener(listener);
+ }
+
+ /**
+ * Remove a listener.
+ * @param listener the listener to remove
+ */
+ public void removeListener(RunListener listener) {
+ notifier.removeListener(listener);
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Request.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Request.java
new file mode 100644
index 0000000000..02db808bb7
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Request.java
@@ -0,0 +1,86 @@
+package org.litejunit.v3.runner;
+
+import org.litejunit.v3.requests.ClassRequest;
+
+
+
+/**
+ * A Request is an abstract description of tests to be run. Older versions of
+ * JUnit did not need such a concept--tests to be run were described either by classes containing
+ * tests or a tree of Tests. However, we want to support filtering and sorting,
+ * so we need a more abstract specification than the tests themselves and a richer
+ * specification than just the classes.
+ *
+ * The flow when JUnit runs tests is that a Request specifies some tests to be run ->
+ * a Runner is created for each class implied by the Request -> the Runner
+ * returns a detailed Description which is a tree structure of the tests to be run.
+ */
+public abstract class Request {
+ /**
+ * Create a Request that, when processed, will run a single test.
+ * This is done by filtering out all other tests. This method is used to support rerunning
+ * single tests.
+ * @param clazz the class of the test
+ * @param methodName the name of the test
+ * @return a Request that will cause a single test be run
+ */
+ /*public static Request method(Class> clazz, String methodName) {
+ Description method= Description.createTestDescription(clazz, methodName);
+ return Request.aClass(clazz).filterWith(method);
+ }*/
+
+ /**
+ * Create a Request that, when processed, will run all the tests
+ * in a class. The odd name is necessary because class is a reserved word.
+ * @param clazz the class containing the tests
+ * @return a Request that will cause all tests in the class to be run
+ */
+ public static Request aClass(Class> clazz) {
+ return new ClassRequest(clazz);
+ }
+
+ /**
+ * Create a Request that, when processed, will run all the tests
+ * in a set of classes.
+ * @param collectionName a name to identify this suite of tests
+ * @param classes the classes containing the tests
+ * @return a Request that will cause all tests in the classes to be run
+ */
+ /*public static Request classes(String collectionName, Class... classes) {
+ return new ClassesRequest(collectionName, classes);
+ }*/
+
+ /*public static Request errorReport(Class> klass, Throwable cause) {
+ return new ErrorReportingRequest(klass, cause);
+ }*/
+
+ public abstract Runner getRunner();
+
+ /*public Request filterWith(Filter filter) {
+ return new FilterRequest(this, filter);
+ }
+
+ public Request filterWith(final Description desiredDescription) {
+ return filterWith(new Filter() {
+ @Override
+ public boolean shouldRun(Description description) {
+ // TODO: test for equality even if we have children?
+ if (description.isTest())
+ return desiredDescription.equals(description);
+ for (Description each : description.getChildren())
+ if (shouldRun(each))
+ return true;
+ return false;
+ }
+
+ @Override
+ public String describe() {
+ return String.format("Method %s", desiredDescription.getDisplayName());
+ }
+ });
+ }
+
+ public Request sortWith(Comparator comparator) {
+ return new SortingRequest(this, comparator);
+ }*/
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Result.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Result.java
new file mode 100644
index 0000000000..591d083f71
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Result.java
@@ -0,0 +1,98 @@
+package org.litejunit.v3.runner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.litejunit.v3.notification.Failure;
+import org.litejunit.v3.notification.RunListener;
+
+
+/**
+ * A Result collects and summarizes information from running multiple
+ * tests. Since tests are expected to run correctly, successful tests are only noted in
+ * the count of tests that ran.
+ */
+public class Result {
+ private int fCount= 0;
+ private int fIgnoreCount= 0;
+ private List fFailures= new ArrayList();
+ private long fRunTime= 0;
+ private long fStartTime;
+
+ /**
+ * @return the number of tests run
+ */
+ public int getRunCount() {
+ return fCount;
+ }
+
+ /**
+ * @return the number of tests that failed during the run
+ */
+ public int getFailureCount() {
+ return fFailures.size();
+ }
+
+ /**
+ * @return the number of milliseconds it took to run the entire suite to run
+ */
+ public long getRunTime() {
+ return fRunTime;
+ }
+
+ /**
+ * @return the Failures describing tests that failed and the problems they encountered
+ */
+ public List getFailures() {
+ return fFailures;
+ }
+
+ /**
+ * @return the number of tests ignored during the run
+ */
+ public int getIgnoreCount() {
+ return fIgnoreCount;
+ }
+
+ /**
+ * @return true if all tests succeeded
+ */
+ public boolean wasSuccessful() {
+ return getFailureCount() == 0;
+ }
+
+ private class Listener extends RunListener {
+ @Override
+ public void testRunStarted(Description description) throws Exception {
+ fStartTime= System.currentTimeMillis();
+ }
+
+ @Override
+ public void testRunFinished(Result result) throws Exception {
+ long endTime= System.currentTimeMillis();
+ fRunTime+= endTime - fStartTime;
+ }
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ fCount++;
+ }
+
+ @Override
+ public void testFailure(Failure failure) throws Exception {
+ fFailures.add(failure);
+ }
+
+ @Override
+ public void testIgnored(Description description) throws Exception {
+ fIgnoreCount++;
+ }
+ }
+
+ /**
+ * Internal use only.
+ */
+ public RunListener createListener() {
+ return new Listener();
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/ResultPrinter.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/ResultPrinter.java
new file mode 100644
index 0000000000..de8a41717c
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/ResultPrinter.java
@@ -0,0 +1,72 @@
+package org.litejunit.v3.runner;
+
+import java.io.PrintStream;
+import java.text.NumberFormat;
+
+import org.litejunit.v3.notification.Failure;
+
+public class ResultPrinter {
+
+ private final PrintStream fWriter;
+
+ public ResultPrinter(){
+ fWriter = System.out;
+ }
+
+ public void print(Result result) {
+ printHeader(result.getRunTime());
+ printFailures(result);
+ printFooter(result);
+ }
+ protected void printHeader(long runTime) {
+ getWriter().println();
+ getWriter().println("Time: " + elapsedTimeAsString(runTime));
+ }
+
+ protected void printFailures(Result result) {
+ if (result.getFailureCount() == 0)
+ return;
+ if (result.getFailureCount() == 1)
+ getWriter().println("There was " + result.getFailureCount() + " failure:");
+ else
+ getWriter().println("There were " + result.getFailureCount() + " failures:");
+ int i= 1;
+ for (Failure each : result.getFailures())
+ printFailure(each, i++);
+ }
+
+ protected void printFailure(Failure failure, int count) {
+ printFailureHeader(failure, count);
+ printFailureTrace(failure);
+ }
+
+ protected void printFailureHeader(Failure failure, int count) {
+ getWriter().println(count + ") " + failure.getTestHeader());
+ }
+
+ protected void printFailureTrace(Failure failure) {
+ getWriter().print(failure.getTrace());
+ }
+
+ protected void printFooter(Result result) {
+ if (result.wasSuccessful()) {
+ getWriter().println();
+ getWriter().print("OK");
+ getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")");
+
+ } else {
+ getWriter().println();
+ getWriter().println("FAILURES!!!");
+ getWriter().println("Tests run: " + result.getRunCount() + ", Failures: " + result.getFailureCount());
+ }
+ getWriter().println();
+ }
+ protected String elapsedTimeAsString(long runTime) {
+ return NumberFormat.getInstance().format((double) runTime / 1000);
+ }
+ private PrintStream getWriter() {
+ return fWriter;
+ }
+
+
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/RunWith.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/RunWith.java
new file mode 100644
index 0000000000..c8ed3d4ff5
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/RunWith.java
@@ -0,0 +1,24 @@
+package org.litejunit.v3.runner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+//TODO add simple exampel
+/**
+ * When you annotate a class with @RunWith, JUnit will invoke
+ * the class it references to run the tests in that class instead of the runner
+ * built into JUnit. We added this feature late in development. While it
+ * seems powerful we expect the runner API to change as we learn how people
+ * really use it. Some of the classes that are currently internal will likely be refined
+ * and become public.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RunWith {
+ /**
+ * @return a Runner class (must have a constructor that takes a single Class to run)
+ */
+ Class extends Runner> value();
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Runner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Runner.java
new file mode 100644
index 0000000000..57ef0faf97
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runner/Runner.java
@@ -0,0 +1,24 @@
+package org.litejunit.v3.runner;
+
+import org.litejunit.v3.notification.RunNotifier;
+
+
+public abstract class Runner {
+ /**
+ * @return a Description showing the tests to be run by the receiver
+ */
+ public abstract Description getDescription();
+
+ /**
+ * Run the tests for this runner.
+ * @param notifier will be notified of events while tests are being run--tests being started, finishing, and failing
+ */
+ public abstract void run(RunNotifier notifier);
+
+ /**
+ * @return the number of tests to be run by the receiver
+ */
+ public int testCount() {
+ return getDescription().testCount();
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/BeforeAndAfterRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/BeforeAndAfterRunner.java
new file mode 100644
index 0000000000..1bcbf40d79
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/BeforeAndAfterRunner.java
@@ -0,0 +1,76 @@
+package org.litejunit.v3.runners;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public abstract class BeforeAndAfterRunner {
+ private static class FailedBefore extends Exception {
+ private static final long serialVersionUID= 1L;
+ }
+
+ private final Class extends Annotation> beforeAnnotation;
+
+ private final Class extends Annotation> afterAnnotation;
+
+ private TestIntrospector testIntrospector;
+
+ private Object test;
+
+ public BeforeAndAfterRunner(Class> testClass,
+ Class extends Annotation> beforeAnnotation,
+ Class extends Annotation> afterAnnotation,
+ Object test) {
+ this.beforeAnnotation= beforeAnnotation;
+ this.afterAnnotation= afterAnnotation;
+ this.testIntrospector= new TestIntrospector(testClass);
+ this.test= test;
+ }
+
+ public void runProtected() {
+ try {
+ runBefores();
+ runUnprotected();
+ } catch (FailedBefore e) {
+ } finally {
+ runAfters();
+ }
+ }
+
+ protected abstract void runUnprotected();
+
+ protected abstract void addFailure(Throwable targetException);
+
+ // Stop after first failed @Before
+ private void runBefores() throws FailedBefore {
+ try {
+ List befores= testIntrospector.getTestMethods(beforeAnnotation);
+ for (Method before : befores)
+ invokeMethod(before);
+ } catch (InvocationTargetException e) {
+ addFailure(e.getTargetException());
+ throw new FailedBefore();
+ } catch (Throwable e) {
+ addFailure(e);
+ throw new FailedBefore();
+ }
+ }
+
+ // Try to run all @Afters regardless
+ private void runAfters() {
+ List afters= testIntrospector.getTestMethods(afterAnnotation);
+ for (Method after : afters)
+ try {
+ invokeMethod(after);
+ } catch (InvocationTargetException e) {
+ addFailure(e.getTargetException());
+ } catch (Throwable e) {
+ addFailure(e); // Untested, but seems impossible
+ }
+ }
+
+ private void invokeMethod(Method method) throws Exception {
+ method.invoke(test);
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/InitializationError.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/InitializationError.java
new file mode 100644
index 0000000000..76e21d02e4
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/InitializationError.java
@@ -0,0 +1,25 @@
+package org.litejunit.v3.runners;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class InitializationError extends Exception {
+ private static final long serialVersionUID= 1L;
+ private final List fErrors;
+
+ public InitializationError(List errors) {
+ fErrors= errors;
+ }
+
+ public InitializationError(Throwable... errors) {
+ this(Arrays.asList(errors));
+ }
+
+ public InitializationError(String string) {
+ this(new Exception(string));
+ }
+
+ public List getCauses() {
+ return fErrors;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassMethodsRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassMethodsRunner.java
new file mode 100644
index 0000000000..adf3b9c40d
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassMethodsRunner.java
@@ -0,0 +1,100 @@
+package org.litejunit.v3.runners;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.litejunit.v3.Test;
+import org.litejunit.v3.notification.Failure;
+import org.litejunit.v3.notification.RunNotifier;
+import org.litejunit.v3.runner.Description;
+import org.litejunit.v3.runner.Runner;
+
+
+
+public class TestClassMethodsRunner extends Runner {
+ private final List testMethods;
+ private final Class> testClass;
+
+ public TestClassMethodsRunner(Class> klass) {
+ testClass= klass;
+ testMethods= new TestIntrospector(testClass).getTestMethods(Test.class);
+ }
+
+ @Override
+ public void run(RunNotifier notifier) {
+ /*if (testMethods.isEmpty())
+ testAborted(notifier, getDescription());*/
+ for (Method method : testMethods)
+ invokeTestMethod(method, notifier);
+ }
+
+ /*private void testAborted(RunNotifier notifier, Description description) {
+ // TODO: duped!
+ // TODO: envious
+ notifier.fireTestStarted(description);
+ notifier.fireTestFailure(new Failure(description, new Exception("No runnable methods")));
+ notifier.fireTestFinished(description);
+ }*/
+
+ @Override
+ public Description getDescription() {
+ Description spec= Description.createSuiteDescription(getName());
+ List testMethods= this.testMethods;
+ for (Method method : testMethods)
+ spec.addChild(methodDescription(method));
+ return spec;
+ }
+
+ protected String getName() {
+ return getTestClass().getName();
+ }
+
+ protected Object createTest() throws Exception {
+ return getTestClass().getConstructor().newInstance();
+ }
+
+ protected void invokeTestMethod(Method method, RunNotifier notifier) {
+ Object test;
+ try {
+ test= createTest();
+ } catch (Exception e) {
+ //testAborted(notifier, methodDescription(method));
+ return;
+ }
+ createMethodRunner(test, method, notifier).run();
+ }
+
+ protected TestMethodRunner createMethodRunner(Object test, Method method, RunNotifier notifier) {
+ return new TestMethodRunner(test, method, notifier, methodDescription(method));
+ }
+
+ protected String testName(Method method) {
+ return method.getName();
+ }
+
+ protected Description methodDescription(Method method) {
+ return Description.createTestDescription(getTestClass(), testName(method));
+ }
+
+ /*public void filter(Filter filter) throws NoTestsRemainException {
+ for (Iterator iter= fTestMethods.iterator(); iter.hasNext();) {
+ Method method= (Method) iter.next();
+ if (!filter.shouldRun(methodDescription(method)))
+ iter.remove();
+ }
+ if (fTestMethods.isEmpty())
+ throw new NoTestsRemainException();
+ }
+
+ public void sort(final Sorter sorter) {
+ Collections.sort(fTestMethods, new Comparator() {
+ public int compare(Method o1, Method o2) {
+ return sorter.compare(methodDescription(o1), methodDescription(o2));
+ }
+ });
+ }*/
+
+ protected Class> getTestClass() {
+ return testClass;
+ }
+}
\ No newline at end of file
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassRunner.java
new file mode 100644
index 0000000000..84c2a072ef
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestClassRunner.java
@@ -0,0 +1,53 @@
+package org.litejunit.v3.runners;
+
+import org.litejunit.v3.AfterClass;
+import org.litejunit.v3.BeforeClass;
+import org.litejunit.v3.notification.Failure;
+import org.litejunit.v3.notification.RunNotifier;
+import org.litejunit.v3.runner.Description;
+import org.litejunit.v3.runner.Runner;
+
+public class TestClassRunner extends Runner {
+ protected final Runner enclosedRunner;
+ private final Class> testClass;
+
+ public TestClassRunner(Class> klass) throws InitializationError {
+ this(klass, new TestClassMethodsRunner(klass));
+ }
+
+ public TestClassRunner(Class> klass, Runner runner) throws InitializationError {
+ testClass= klass;
+ enclosedRunner= runner;
+
+ }
+
+
+
+ @Override
+ public void run(final RunNotifier notifier) {
+ BeforeAndAfterRunner runner = new BeforeAndAfterRunner(getTestClass(),
+ BeforeClass.class, AfterClass.class, null) {
+ @Override
+ protected void runUnprotected() {
+ enclosedRunner.run(notifier);
+ }
+
+ // TODO: looks very similar to other method of BeforeAfter, now
+ @Override
+ protected void addFailure(Throwable targetException) {
+ notifier.fireTestFailure(new Failure(getDescription(), targetException));
+ }
+ };
+
+ runner.runProtected();
+ }
+
+ @Override
+ public Description getDescription() {
+ return enclosedRunner.getDescription();
+ }
+
+ protected Class> getTestClass() {
+ return testClass;
+ }
+}
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestIntrospector.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestIntrospector.java
new file mode 100644
index 0000000000..1dda424d7f
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestIntrospector.java
@@ -0,0 +1,82 @@
+package org.litejunit.v3.runners;
+
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.litejunit.v3.Before;
+import org.litejunit.v3.BeforeClass;
+import org.litejunit.v3.Ignore;
+import org.litejunit.v3.Test;
+import org.litejunit.v3.Test.None;
+
+
+
+public class TestIntrospector {
+ private final Class< ?> testClass;
+
+ public TestIntrospector(Class> testClass) {
+ this.testClass= testClass;
+ }
+
+ public List getTestMethods(Class extends Annotation> annotationClass) {
+ List results= new ArrayList();
+
+ //for (Class eachClass : getSuperClasses(testClass)) {
+ Method[] methods= testClass.getDeclaredMethods();
+ for (Method method : methods) {
+ Annotation annotation= method.getAnnotation(annotationClass);
+ if (annotation != null && ! isShadowed(method, results))
+ results.add(method);
+ }
+ //}
+ if (runsTopToBottom(annotationClass))
+ Collections.reverse(results);
+ return results;
+ }
+
+ public boolean isIgnored(Method eachMethod) {
+ return eachMethod.getAnnotation(Ignore.class) != null;
+ }
+
+ private boolean runsTopToBottom(Class< ? extends Annotation> annotation) {
+ return annotation.equals(Before.class) || annotation.equals(BeforeClass.class);
+ }
+
+ private boolean isShadowed(Method method, List results) {
+ for (Method m : results) {
+ if (m.getName().equals(method.getName()))
+ return true;
+ }
+ return false;
+ }
+
+ /*private List getSuperClasses(Class< ?> testClass) {
+ ArrayList results= new ArrayList();
+ Class> current= testClass;
+ while (current != null) {
+ results.add(current);
+ current= current.getSuperclass();
+ }
+ return results;
+ }*/
+
+ long getTimeout(Method method) {
+ Test annotation= method.getAnnotation(Test.class);
+ long timeout= annotation.timeout();
+ return timeout;
+ }
+
+ Class extends Throwable> expectedException(Method method) {
+ Test annotation= method.getAnnotation(Test.class);
+ if (annotation.expected() == None.class)
+ return null;
+ else
+ return annotation.expected();
+ }
+
+}
+
diff --git a/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestMethodRunner.java b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestMethodRunner.java
new file mode 100644
index 0000000000..7034a4c812
--- /dev/null
+++ b/liuxin/ood/ood-assignment/src/main/java/org/litejunit/v3/runners/TestMethodRunner.java
@@ -0,0 +1,122 @@
+package org.litejunit.v3.runners;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.litejunit.v3.After;
+import org.litejunit.v3.Before;
+import org.litejunit.v3.notification.Failure;
+import org.litejunit.v3.notification.RunNotifier;
+import org.litejunit.v3.runner.Description;
+
+
+
+public class TestMethodRunner extends BeforeAndAfterRunner {
+ private final Object test;
+ private final Method method;
+ private final RunNotifier notifier;
+ private final TestIntrospector testIntrospector;
+ private final Description description;
+
+ public TestMethodRunner(Object test, Method method, RunNotifier notifier, Description description) {
+ super(test.getClass(), Before.class, After.class, test);
+ this.test= test;
+ this.method= method;
+ this.notifier= notifier;
+ testIntrospector= new TestIntrospector(test.getClass());
+ this.description= description;
+ }
+
+ public void run() {
+ /*if (testIntrospector.isIgnored(method)) {
+ notifier.fireTestIgnored(description);
+ return;
+ }*/
+ notifier.fireTestStarted(description);
+ try {
+ /*long timeout= testIntrospector.getTimeout(method);
+ if (timeout > 0)
+ runWithTimeout(timeout);
+ else*/
+ runMethod();
+ } finally {
+ notifier.fireTestFinished(description);
+ }
+ }
+
+ /*private void runWithTimeout(long timeout) {
+ ExecutorService service= Executors.newSingleThreadExecutor();
+ Callable