[
  {
    "path": ".classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"src\" path=\"test/end-to-end\"/>\n\t<classpathentry kind=\"src\" path=\"test/unit\"/>\n\t<classpathentry kind=\"src\" path=\"test/integration\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/deploy/commons-io-1.4.jar\" sourcepath=\"lib/develop/commons-io-1.4-sources.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/deploy/commons-lang-2.4.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/deploy/smack_3_1_0.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/deploy/smackx_3_1_0.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/cglib-nodep-2.2.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/junit-4.6-src.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/junit-dep-4.6.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/objenesis-1.0.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/windowlicker-core-DEV.jar\" sourcepath=\"/windowlicker/src/swing/main\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/windowlicker-swing-DEV.jar\" sourcepath=\"/windowlicker/src/swing/main\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/jmock-legacy-2.6-SNAPSHOT.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/jmock-2.6-SNAPSHOT.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/jmock-junit4-2.6-SNAPSHOT.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/hamcrest-core-SNAPSHOT.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/develop/hamcrest-library-SNAPSHOT.jar\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER\"/>\n\t<classpathentry kind=\"output\" path=\"bin\"/>\n</classpath>\n"
  },
  {
    "path": ".project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>auction-example-06</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n\t</natures>\n</projectDescription>\n"
  },
  {
    "path": "build.xml",
    "content": "<project name=\"Auction Sniper\" default=\"build\">\n    <property name=\"build.dir\" location=\"build\" />\n    <property name=\"src.dir\" location=\"src\" />\n    <property name=\"test.dir\" location=\"test\"/>\n    <property name=\"lib.dir\" value=\"lib\" />\n    <property name=\"app.classes.dir\" location=\"${build.dir}/classes/app\" />\n    <property name=\"test.classes.dir\" location=\"${build.dir}/classes/test\" />\n    \n    <path id=\"app.lib.path\">\n        <fileset dir=\"${lib.dir}/deploy\" includes=\"*.jar\"/>\n    </path>\n\n    <path id=\"test.lib.path\">\n        <fileset dir=\"${lib.dir}/develop\" includes=\"*.jar\" excludes=\"*-src.jar\"/>\n        <path location=\"${app.classes.dir}\" />\n        <path refid=\"app.lib.path\"/>\n    </path>\n\n    <target name=\"clean\">\n    \t<delete dir=\"${build.dir}\" quiet=\"true\" />\n    </target>\n    \n    <target name=\"app.compile\">\n        <property name=\"app.src.dir\" location=\"${src.dir}\" />\n    \t<mkdir dir=\"${app.classes.dir}\" />\n        <javac destdir=\"${app.classes.dir}\"\n               srcdir=\"${app.src.dir}\"\n               classpathref=\"app.lib.path\" \n        \t   debug=\"on\"/>\n    </target>\n\n    <target name=\"test.compile\"\n        \tdepends=\"app.compile\">\n        <property name=\"test.src.dir\" location=\"${test.dir}/end-to-end\" />\n    \t<mkdir dir=\"${test.classes.dir}\" />\n        <javac destdir=\"${test.classes.dir}\"\n               srcdir=\"${test.src.dir}\"\n               classpathref=\"test.lib.path\"\n               debug=\"on\"/>\n    </target>\n    \n    <target name=\"openfire.check\">\n        <waitfor checkevery=\"1\" checkeveryunit=\"second\" maxwait=\"20\" timeoutproperty=\"openfire.is.down\">\n            <http url=\"http://localhost:9090\" />\n        </waitfor>\n    </target>\n    \n    <target name=\"test.run\"\n    \t\tdescription=\"Run the tests\" \n    \t\tdepends=\"test.compile, openfire.check\" >\n        <fail message=\"OpenFire is not running\" if=\"openfire.is.down\"/>\n        <property name=\"test.reports.dir\" location=\"${build.dir}/testreports\"/>\n        <mkdir dir=\"${test.reports.dir}\"/>\n        <junit>\n            <batchtest todir=\"${test.reports.dir}\" haltonfailure=\"true\" haltonerror=\"true\">\n                <formatter type=\"plain\"/>\n                <fileset dir=\"${test.dir}/end-to-end\" includes=\"**/*Test.java\" />\n            </batchtest>\n            <classpath>\n                <path refid=\"test.lib.path\" />\n                <path location=\"${test.classes.dir}\" />\n            </classpath>\n        </junit>\n    </target>\n    \n    <target name=\"build\"\n    \tdescription=\"Clean, build, and full test\" \n   \t\tdepends=\"clean, test.run\" />\n</project>"
  },
  {
    "path": "license.txt",
    "content": "This project is Copyright 2009 Stephen Freeman and Nathaniel Pryce\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "src/auctionsniper/Auction.java",
    "content": "package auctionsniper;\n\npublic interface Auction {\n\n  void join();\n  void bid(int amount);\n  void addAuctionEventListener(AuctionEventListener listener);\n}\n"
  },
  {
    "path": "src/auctionsniper/AuctionEventListener.java",
    "content": "package auctionsniper;\n\nimport java.util.EventListener;\n\npublic interface AuctionEventListener extends EventListener {\n  enum PriceSource {\n    FromSniper, FromOtherBidder;\n  };\n  \n  void auctionClosed();\n  void currentPrice(int price, int increment, PriceSource priceSource);\n  void auctionFailed();\n}\n"
  },
  {
    "path": "src/auctionsniper/AuctionHouse.java",
    "content": "package auctionsniper;\n\nimport auctionsniper.UserRequestListener.Item;\n\npublic interface AuctionHouse {\n  Auction auctionFor(Item item); \n}\n"
  },
  {
    "path": "src/auctionsniper/AuctionSniper.java",
    "content": "package auctionsniper;\n\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.util.Announcer;\n\npublic class AuctionSniper implements AuctionEventListener {\n  private final Announcer<SniperListener> listeners = Announcer.to(SniperListener.class);\n  private final Auction auction;\n  private SniperSnapshot snapshot;\n  private final Item item; \n    \n  public AuctionSniper(Item item, Auction auction) {\n    this.item = item;\n    this.auction = auction;\n    this.snapshot = SniperSnapshot.joining(item.identifier);\n  }\n\n  public void addSniperListener(SniperListener listener) {\n    listeners.addListener(listener);\n  }\n  \n  public void auctionClosed() {\n    snapshot = snapshot.closed();\n    notifyChange();\n  }\n\n  public void auctionFailed() {\n    snapshot = snapshot.failed(); \n    notifyChange();\n  }\n  \n  public void currentPrice(int price, int increment, PriceSource priceSource) {\n    switch(priceSource) {\n    case FromSniper:\n      snapshot = snapshot.winning(price); \n      break;\n    case FromOtherBidder:\n      int bid = price + increment;\n      if (item.allowsBid(bid)) {\n        auction.bid(bid);\n        snapshot = snapshot.bidding(price, bid);\n      } else {\n        snapshot = snapshot.losing(price);\n      }\n      break;\n    }\n    notifyChange();\n  }\n\n  public SniperSnapshot getSnapshot() {\n    return snapshot;\n  }\n  \n  private void notifyChange() {\n    listeners.announce().sniperStateChanged(snapshot);\n  }\n\n}\n"
  },
  {
    "path": "src/auctionsniper/Main.java",
    "content": "package auctionsniper;\n\nimport java.awt.event.WindowAdapter;\nimport java.awt.event.WindowEvent;\n\nimport javax.swing.SwingUtilities;\n\nimport auctionsniper.ui.MainWindow;\nimport auctionsniper.xmpp.XMPPAuctionHouse;\n\npublic class Main {\n  private static final int ARG_HOSTNAME = 0;\n  private static final int ARG_USERNAME = 1;\n  private static final int ARG_PASSWORD = 2;\n\n  private final SniperPortfolio portfolio = new SniperPortfolio(); \n\n  private MainWindow ui;\n\n  public Main() throws Exception {\n    startUserInterface();\n  }\n\n  public static void main(String... args) throws Exception {\n    Main main = new Main();\n    XMPPAuctionHouse auctionHouse = XMPPAuctionHouse.connect(args[ARG_HOSTNAME], args[ARG_USERNAME], args[ARG_PASSWORD]); \n    main.disconnectWhenUICloses(auctionHouse);\n    main.addUserRequestListenerFor(auctionHouse);\n  }\n\n  private void startUserInterface() throws Exception {\n    SwingUtilities.invokeAndWait(new Runnable() {\n      public void run() {\n        ui = new MainWindow(portfolio);\n      }\n    });\n  }\n\n  private void disconnectWhenUICloses(final XMPPAuctionHouse auctionHouse) { \n    ui.addWindowListener(new WindowAdapter() { \n      @Override public void windowClosed(WindowEvent e) { \n        auctionHouse.disconnect(); \n      } \n    }); \n  } \n\n  private void addUserRequestListenerFor(final AuctionHouse auctionHouse) {\n    ui.addUserRequestListener(new SniperLauncher(auctionHouse, portfolio)); \n\n  } \n}\n"
  },
  {
    "path": "src/auctionsniper/SniperCollector.java",
    "content": "package auctionsniper;\n\npublic interface SniperCollector {\n  void addSniper(AuctionSniper sniper);\n}\n"
  },
  {
    "path": "src/auctionsniper/SniperLauncher.java",
    "content": "package auctionsniper;\n\n\npublic class SniperLauncher implements UserRequestListener {\n  private final AuctionHouse auctionHouse;\n  private final SniperCollector collector;\n\n  public SniperLauncher(AuctionHouse auctionHouse, SniperCollector collector) {\n    this.auctionHouse = auctionHouse;\n    this.collector = collector;\n  }\n\n  public void joinAuction(Item item) { \n    Auction auction = auctionHouse.auctionFor(item);\n    AuctionSniper sniper = new AuctionSniper(item, auction); \n    auction.addAuctionEventListener(sniper); \n    collector.addSniper(sniper); \n    auction.join(); \n  }\n}"
  },
  {
    "path": "src/auctionsniper/SniperListener.java",
    "content": "package auctionsniper;\n\nimport java.util.EventListener;\n\npublic interface SniperListener extends EventListener { \n  void sniperStateChanged(SniperSnapshot snapshot);\n}"
  },
  {
    "path": "src/auctionsniper/SniperPortfolio.java",
    "content": "package auctionsniper;\n\nimport java.util.ArrayList;\nimport java.util.EventListener;\n\nimport auctionsniper.util.Announcer;\n\npublic class SniperPortfolio implements SniperCollector {\n  public interface PortfolioListener extends EventListener {\n    void sniperAdded(AuctionSniper sniper);\n  }\n \n  private final Announcer<PortfolioListener> announcer = Announcer.to(PortfolioListener.class);\n  private final ArrayList<AuctionSniper> snipers = new ArrayList<AuctionSniper>();\n  \n  public void addSniper(AuctionSniper sniper) {\n    snipers.add(sniper);\n    announcer.announce().sniperAdded(sniper);\n  }\n\n  public void addPortfolioListener(PortfolioListener listener) {\n    announcer.addListener(listener);\n  }\n}\n"
  },
  {
    "path": "src/auctionsniper/SniperSnapshot.java",
    "content": "package auctionsniper;\n\nimport org.apache.commons.lang.builder.EqualsBuilder;\nimport org.apache.commons.lang.builder.HashCodeBuilder;\nimport org.apache.commons.lang.builder.ToStringBuilder;\n\npublic class SniperSnapshot {\n  public final String itemId;\n  public final int lastPrice;\n  public final int lastBid;\n  public final SniperState state;\n  \n  public SniperSnapshot(String itemId, int lastPrice, int lastBid, SniperState state) {\n    this.itemId = itemId;\n    this.lastPrice = lastPrice;\n    this.lastBid = lastBid;\n    this.state = state;\n  }\n  \n  @Override\n  public boolean equals(Object obj) {\n    return EqualsBuilder.reflectionEquals(this, obj);\n  }\n  @Override\n  public int hashCode() {\n    return HashCodeBuilder.reflectionHashCode(this);\n  }\n  @Override\n  public String toString() {\n    return ToStringBuilder.reflectionToString(this);\n  }\n\n  public static SniperSnapshot joining(String itemId) {\n    return new SniperSnapshot(itemId, 0, 0, SniperState.JOINING);\n  }\n\n  public SniperSnapshot bidding(int newLastPrice, int newLastBid) {\n    return new SniperSnapshot(itemId, newLastPrice, newLastBid, SniperState.BIDDING);\n  }\n\n  public SniperSnapshot winning(int newLastPrice) {\n    return new SniperSnapshot(itemId, newLastPrice, lastBid, SniperState.WINNING);\n  }\n\n  public SniperSnapshot losing(int newLastPrice) {\n    return new SniperSnapshot(itemId, newLastPrice, lastBid, SniperState.LOSING);\n  }\n\n  public SniperSnapshot closed() {\n    return new SniperSnapshot(itemId, lastPrice, lastBid, state.whenAuctionClosed());\n  }\n\n  public SniperSnapshot failed() {\n    return new SniperSnapshot(itemId, 0, 0, SniperState.FAILED);\n  }\n\n  public boolean isForSameItemAs(SniperSnapshot sniperSnapshot) {\n    return itemId.equals(sniperSnapshot.itemId);\n  }\n\n\n\n}"
  },
  {
    "path": "src/auctionsniper/SniperState.java",
    "content": "package auctionsniper;\n\nimport auctionsniper.util.Defect;\n\npublic enum SniperState { \n  JOINING {\n    @Override public SniperState whenAuctionClosed() { return LOST; } \n  },\n  BIDDING { \n    @Override public SniperState whenAuctionClosed() { return LOST; } \n  }, \n  WINNING { \n    @Override public SniperState whenAuctionClosed() { return WON; } \n  }, \n  LOSING {\n    @Override public SniperState whenAuctionClosed() { return LOST; } \n  },\n  LOST, \n  WON,\n  FAILED;\n\n  public SniperState whenAuctionClosed() { \n    throw new Defect(\"Auction is already closed\"); \n  } \n}"
  },
  {
    "path": "src/auctionsniper/UserRequestListener.java",
    "content": "package auctionsniper;\n\nimport java.util.EventListener;\n\nimport org.apache.commons.lang.builder.EqualsBuilder;\nimport org.apache.commons.lang.builder.HashCodeBuilder;\n\npublic interface UserRequestListener extends EventListener {\n  void joinAuction(Item item);\n  \n  public static class Item {\n    public final String identifier;\n    public final int stopPrice;\n\n    public Item(String identifier, int stopPrice) { \n      this.identifier = identifier;\n      this.stopPrice = stopPrice; \n    }\n\n    public boolean allowsBid(int bid) {\n      return bid <= stopPrice;\n    } \n\n    @Override\n    public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); }\n    @Override\n    public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); }\n    @Override\n    public String toString() { return \"Item: \" + identifier + \", stop price: \" + stopPrice; }\n\n  }\n}\n"
  },
  {
    "path": "src/auctionsniper/ui/Column.java",
    "content": "package auctionsniper.ui;\n\nimport auctionsniper.SniperSnapshot;\n\npublic enum Column { \n  ITEM_IDENTIFIER(\"Item\") { \n    @Override public Object valueIn(SniperSnapshot snapshot) { \n      return snapshot.itemId; \n    } \n  }, \n  LAST_PRICE(\"Last Price\") { \n    @Override public Object valueIn(SniperSnapshot snapshot) { \n      return snapshot.lastPrice; \n    } \n  }, \n  LAST_BID(\"Last Bid\") { \n    @Override public Object valueIn(SniperSnapshot snapshot) { \n      return snapshot.lastBid; \n    }    \n  }, \n  SNIPER_STATE(\"State\") { \n    @Override public Object valueIn(SniperSnapshot snapshot) { \n      return SnipersTableModel.textFor(snapshot.state); \n    }    \n  }; \n  \n  abstract public Object valueIn(SniperSnapshot snapshot); \n  \n  public final String name;\n  \n  private Column(String name) { \n    this.name = name; \n  } \n\n  public static Column at(int offset) { return values()[offset]; } \n}\n"
  },
  {
    "path": "src/auctionsniper/ui/MainWindow.java",
    "content": "package auctionsniper.ui;\n\nimport java.awt.BorderLayout;\nimport java.awt.Container;\nimport java.awt.FlowLayout;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.text.NumberFormat;\n\nimport javax.swing.JButton;\nimport javax.swing.JFormattedTextField;\nimport javax.swing.JFrame;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTable;\nimport javax.swing.JTextField;\n\nimport auctionsniper.UserRequestListener;\nimport auctionsniper.SniperPortfolio;\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.util.Announcer;\n\n\npublic class MainWindow extends JFrame { \n  public static final String APPLICATION_TITLE = \"Auction Sniper\";\n  private static final String SNIPERS_TABLE_NAME = \"Snipers Table\";\n  public static final String MAIN_WINDOW_NAME = \"Auction Sniper Main\";\n  public static final String NEW_ITEM_ID_NAME = \"item id\";\n  public static final String JOIN_BUTTON_NAME = \"join button\";\n  public static final String NEW_ITEM_STOP_PRICE_NAME = \"stop price\";\n  \n  private final Announcer<UserRequestListener> userRequests = Announcer.to(UserRequestListener.class); \n\n  \n  public MainWindow(SniperPortfolio portfolio){ \n    super(\"Auction Sniper\"); \n    setName(MainWindow.MAIN_WINDOW_NAME); \n    fillContentPane(makeSnipersTable(portfolio), makeControls());\n    pack(); \n    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); \n    setVisible(true); \n  } \n  \n  public void addUserRequestListener(UserRequestListener userRequestListener) {\n    userRequests.addListener(userRequestListener); \n  } \n\n  private void fillContentPane(JTable snipersTable, JPanel controls) { \n    final Container contentPane = getContentPane(); \n    contentPane.setLayout(new BorderLayout()); \n    contentPane.add(controls, BorderLayout.NORTH); \n    contentPane.add(new JScrollPane(snipersTable), BorderLayout.CENTER); \n  } \n  \n  private JPanel makeControls() { \n    final JTextField itemIdField = itemIdField();\n    final JFormattedTextField stopPriceField = stopPriceField();\n\n    JPanel controls = new JPanel(new FlowLayout()); \n    controls.add(itemIdField); \n    controls.add(stopPriceField);\n\n    JButton joinAuctionButton = new JButton(\"Join Auction\"); \n    joinAuctionButton.setName(JOIN_BUTTON_NAME); \n    \n    joinAuctionButton.addActionListener(new ActionListener() { \n      public void actionPerformed(ActionEvent e) { \n        userRequests.announce().joinAuction(new Item(itemId(), stopPrice())); \n      } \n      private String itemId() {\n        return itemIdField.getText();\n      }\n      private int stopPrice() { \n        return ((Number)stopPriceField.getValue()).intValue(); \n      } \n    }); \n    controls.add(joinAuctionButton); \n    \n    return controls; \n  } \n\n  private JTextField itemIdField() {\n    JTextField itemIdField = new JTextField();\n    itemIdField.setColumns(10);\n    itemIdField.setName(NEW_ITEM_ID_NAME);\n    return itemIdField;\n  }\n\n  private JFormattedTextField stopPriceField() {\n    JFormattedTextField stopPriceField = new JFormattedTextField(NumberFormat.getIntegerInstance());\n    stopPriceField.setColumns(7);\n    stopPriceField.setName(NEW_ITEM_STOP_PRICE_NAME);\n    return stopPriceField;\n  }\n\n  private JTable makeSnipersTable(SniperPortfolio portfolio) { \n    SnipersTableModel model = new SnipersTableModel();\n    portfolio.addPortfolioListener(model);\n    JTable snipersTable = new JTable(model); \n    snipersTable.setName(SNIPERS_TABLE_NAME); \n    return snipersTable; \n  }\n\n} \n"
  },
  {
    "path": "src/auctionsniper/ui/SnipersTableModel.java",
    "content": "package auctionsniper.ui;\n\nimport java.util.ArrayList;\n\nimport javax.swing.table.AbstractTableModel;\n\nimport auctionsniper.AuctionSniper;\nimport auctionsniper.SniperListener;\nimport auctionsniper.SniperSnapshot;\nimport auctionsniper.SniperState;\nimport auctionsniper.SniperPortfolio.PortfolioListener;\nimport auctionsniper.util.Defect;\n\npublic class SnipersTableModel extends AbstractTableModel implements SniperListener, PortfolioListener {\n  private final static String[] STATUS_TEXT = { \n    \"Joining\", \"Bidding\", \"Winning\", \"Losing\", \"Lost\", \"Won\", \"Failed\" \n  };\n  private ArrayList<SniperSnapshot> snapshots = new ArrayList<SniperSnapshot>();\n\n  public int getColumnCount() { \n    return Column.values().length; \n  } \n  \n  public int getRowCount() { \n    return snapshots.size();\n  }\n\n  @Override public String getColumnName(int column) { \n    return Column.at(column).name; \n  } \n\n  public Object getValueAt(int rowIndex, int columnIndex) {\n    return Column.at(columnIndex).valueIn(snapshots.get(rowIndex)); \n  } \n\n  public static String textFor(SniperState state) { \n    return STATUS_TEXT[state.ordinal()]; \n  }\n  \n  public void sniperStateChanged(SniperSnapshot newSnapshot) {\n    for (int i = 0; i < snapshots.size(); i++) {\n      if (newSnapshot.isForSameItemAs(snapshots.get(i))) {\n        snapshots.set(i, newSnapshot); \n        fireTableRowsUpdated(i, i);\n        return;\n      }\n    }\n    throw new Defect(\"No existing Sniper state for \" + newSnapshot.itemId);\n  }\n\n  public void sniperAdded(AuctionSniper sniper) {\n    addSniperSnapshot(sniper.getSnapshot());\n    sniper.addSniperListener(new SwingThreadSniperListener(this));\n  } \n\n  private void addSniperSnapshot(SniperSnapshot newSniper) {\n    snapshots.add(newSniper);\n    int row = snapshots.size() - 1;\n    fireTableRowsInserted(row, row);\n  }\n}\n"
  },
  {
    "path": "src/auctionsniper/ui/SwingThreadSniperListener.java",
    "content": "/**\n * \n */\npackage auctionsniper.ui;\n\nimport javax.swing.SwingUtilities;\n\nimport auctionsniper.SniperListener;\nimport auctionsniper.SniperSnapshot;\n\npublic class SwingThreadSniperListener implements SniperListener {\n  private final SniperListener delegate;\n  public SwingThreadSniperListener(SniperListener delegate) {\n    this.delegate = delegate;\n  }\n  public void sniperStateChanged(final SniperSnapshot snapshot) { \n    SwingUtilities.invokeLater(new Runnable() { \n      public void run() { \n        delegate.sniperStateChanged(snapshot); \n      } \n    }); \n  }\n}"
  },
  {
    "path": "src/auctionsniper/util/Announcer.java",
    "content": "package auctionsniper.util;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.EventListener;\nimport java.util.List;\n\npublic class Announcer<T extends EventListener> {\n\tprivate final T proxy;\n\tprivate final List<T> listeners = new ArrayList<T>();\n\t\n\t\n\tpublic Announcer(Class<? extends T> listenerType) {\n\t\tproxy = listenerType.cast(Proxy.newProxyInstance(\n\t\t\tlistenerType.getClassLoader(), \n\t\t\tnew Class<?>[]{listenerType}, \n\t\t\tnew InvocationHandler() {\n\t\t\t\tpublic Object invoke(Object aProxy, Method method, Object[] args) throws Throwable {\n\t\t\t\t\tannounce(method, args);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}));\n\t}\n\t\n\tpublic void addListener(T listener) {\n\t\tlisteners.add(listener);\n\t}\n\t\n\tpublic void removeListener(T listener) {\n\t\tlisteners.remove(listener);\n\t}\n\t\n\tpublic T announce() {\n\t\treturn proxy;\n\t}\n\t\n\tprivate void announce(Method m, Object[] args) {\n\t\ttry {\n\t\t\tfor (T listener : listeners) {\n\t\t\t\tm.invoke(listener, args);\n\t\t\t}\n\t\t}\n\t\tcatch (IllegalAccessException e) {\n\t\t\tthrow new IllegalArgumentException(\"could not invoke listener\", e);\n\t\t}\n\t\tcatch (InvocationTargetException e) {\n\t\t\tThrowable cause = e.getCause();\n\t\t\t\n\t\t\tif (cause instanceof RuntimeException) {\n\t\t\t\tthrow (RuntimeException)cause;\n\t\t\t} \n\t\t\telse if (cause instanceof Error) {\n\t\t\t\tthrow (Error)cause;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new UnsupportedOperationException(\"listener threw exception\", cause);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static <T extends EventListener> Announcer<T> to(Class<? extends T> listenerType) {\n\t\treturn new Announcer<T>(listenerType);\n\t}\n}\n"
  },
  {
    "path": "src/auctionsniper/util/Defect.java",
    "content": "package auctionsniper.util;\n\npublic class Defect extends RuntimeException {\n\n  public Defect() {\n    super();\n  }\n\n  public Defect(String message, Throwable cause) {\n    super(message, cause);\n  }\n\n  public Defect(String message) {\n    super(message);\n  }\n\n  public Defect(Throwable cause) {\n    super(cause);\n  }\n\n}\n"
  },
  {
    "path": "src/auctionsniper/xmpp/AuctionMessageTranslator.java",
    "content": "package auctionsniper.xmpp;\n\nimport static auctionsniper.AuctionEventListener.PriceSource.FromOtherBidder;\nimport static auctionsniper.AuctionEventListener.PriceSource.FromSniper;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jivesoftware.smack.Chat;\nimport org.jivesoftware.smack.MessageListener;\nimport org.jivesoftware.smack.packet.Message;\n\nimport auctionsniper.AuctionEventListener;\nimport auctionsniper.AuctionEventListener.PriceSource;\n\npublic class AuctionMessageTranslator implements MessageListener { \n  private final AuctionEventListener listener;\n  private final String sniperId;\n  private final XMPPFailureReporter failureReporter;\n\n  public AuctionMessageTranslator(String sniperId, AuctionEventListener listener, XMPPFailureReporter failureReporter) {\n    this.sniperId = sniperId;\n    this.listener = listener;\n    this.failureReporter = failureReporter;\n  }\n\n  public void processMessage(Chat chat, Message message) { \n    String messageBody = message.getBody();\n    try {\n      translate(messageBody);\n    } catch (Exception parseException) {\n      failureReporter.cannotTranslateMessage(sniperId, messageBody, parseException);\n      listener.auctionFailed();\n    } \n  }\n\n  private void translate(String messageBody) throws Exception {\n    AuctionEvent event = AuctionEvent.from(messageBody);\n    \n    String eventType = event.type();\n    if (\"CLOSE\".equals(eventType)) { \n      listener.auctionClosed(); \n    } if (\"PRICE\".equals(eventType)) { \n      listener.currentPrice(event.currentPrice(), event.increment(), \n                            event.isFrom(sniperId)); \n    }\n  } \n  \n  private static class AuctionEvent {\n    private final Map<String, String> fields = new HashMap<String, String>();  \n    public String type() throws MissingValueException { return get(\"Event\"); }\n    public int currentPrice() throws Exception { return getInt(\"CurrentPrice\"); }\n    public int increment() throws Exception { return getInt(\"Increment\"); }\n    public PriceSource isFrom(String sniperId) throws MissingValueException {\n      return sniperId.equals(bidder()) ? FromSniper : FromOtherBidder;\n    }\n    \n    private String bidder() throws MissingValueException { return get(\"Bidder\"); }\n    private int getInt(String fieldName) throws Exception {\n      return Integer.parseInt(get(fieldName));\n    }\n    private String get(String fieldName) throws MissingValueException { \n      final String value = fields.get(fieldName);\n      if (value == null) {\n        throw new MissingValueException(fieldName);\n      }\n      return value; \n    }\n\n    private void addField(String field) {\n      String[] pair = field.split(\":\");\n      fields.put(pair[0].trim(), pair[1].trim());\n    }\n\n    static AuctionEvent from(String messageBody) {\n      AuctionEvent event = new AuctionEvent();\n      for (String field : fieldsIn(messageBody)) {\n        event.addField(field);\n      }\n      return event;\n    }\n    \n    static String[] fieldsIn(String messageBody) {\n      return messageBody.split(\";\");\n    }\n  }\n  private static class MissingValueException extends Exception {\n    public MissingValueException(String fieldName) {\n      super(\"Missing value for \" + fieldName);\n    }\n  }\n} \n"
  },
  {
    "path": "src/auctionsniper/xmpp/LoggingXMPPFailureReporter.java",
    "content": "package auctionsniper.xmpp;\n\nimport java.util.logging.Logger;\n\npublic class LoggingXMPPFailureReporter implements XMPPFailureReporter {\n  private static final String MESSAGE_FORMAT = \"<%s> Could not translate message \\\"%s\\\" because \\\"%s\\\"\";\n  private final Logger logger;\n  \n  public LoggingXMPPFailureReporter(Logger logger) {\n    this.logger = logger;\n  }\n\n  public void cannotTranslateMessage(String auctionId, String failedMessage, Exception exception) {\n    logger.severe(String.format(MESSAGE_FORMAT, auctionId, failedMessage, exception.toString()));\n  }\n}\n"
  },
  {
    "path": "src/auctionsniper/xmpp/XMPPAuction.java",
    "content": "package auctionsniper.xmpp;\n\nimport org.jivesoftware.smack.Chat;\nimport org.jivesoftware.smack.XMPPConnection;\nimport org.jivesoftware.smack.XMPPException;\n\nimport auctionsniper.Auction;\nimport auctionsniper.AuctionEventListener;\nimport auctionsniper.util.Announcer;\n\npublic class XMPPAuction implements Auction { \n  public static final String JOIN_COMMAND_FORMAT = \"SOLVersion: 1.1; Command: JOIN;\";\n  public static final String BID_COMMAND_FORMAT = \"SOLVersion: 1.1; Command: BID; Price: %d;\";\n\n  private final Announcer<AuctionEventListener> auctionEventListeners = Announcer.to(AuctionEventListener.class);\n  private final Chat chat;\n  private final XMPPFailureReporter failureReporter;\n  \n  public XMPPAuction(XMPPConnection connection, String auctionJID, XMPPFailureReporter failureReporter) { \n    this.failureReporter = failureReporter;\n    AuctionMessageTranslator translator = translatorFor(connection);\n    this.chat = connection.getChatManager().createChat( auctionJID, translator);\n    addAuctionEventListener(chatDisconnectorFor(translator));\n  }\n  \n  public void bid(int amount) { \n    sendMessage(String.format(BID_COMMAND_FORMAT, amount)); \n  } \n  public void join() { \n    sendMessage(JOIN_COMMAND_FORMAT); \n  } \n \n  public void addAuctionEventListener(AuctionEventListener listener) {\n    auctionEventListeners.addListener(listener);\n  }\n\n  private AuctionMessageTranslator translatorFor(XMPPConnection connection) {\n    return new AuctionMessageTranslator(connection.getUser(), auctionEventListeners.announce(), failureReporter);\n  } \n\n  private AuctionEventListener \n  chatDisconnectorFor(final AuctionMessageTranslator translator) { \n    return new AuctionEventListener() { \n      public void auctionFailed() { \n        chat.removeMessageListener(translator); \n      }\n      public void auctionClosed() { }\n      public void currentPrice(int price, int increment, PriceSource priceSource) { }\n    }; \n  } \n  private void sendMessage(final String message) { \n    try { \n      chat.sendMessage(message); \n    } catch (XMPPException e) { \n      e.printStackTrace(); \n    } \n  } \n  \n} \n"
  },
  {
    "path": "src/auctionsniper/xmpp/XMPPAuctionException.java",
    "content": "package auctionsniper.xmpp;\n\npublic class XMPPAuctionException extends Exception {\n\n  public XMPPAuctionException(String message, Exception cause) {\n    super(message, cause);\n  }\n\n}\n"
  },
  {
    "path": "src/auctionsniper/xmpp/XMPPAuctionHouse.java",
    "content": "package auctionsniper.xmpp;\n\nimport java.util.logging.FileHandler;\nimport java.util.logging.Logger;\nimport java.util.logging.SimpleFormatter;\n\nimport org.apache.commons.io.FilenameUtils;\nimport org.jivesoftware.smack.XMPPConnection;\nimport org.jivesoftware.smack.XMPPException;\n\nimport auctionsniper.Auction;\nimport auctionsniper.AuctionHouse;\nimport auctionsniper.UserRequestListener.Item;\n\npublic class XMPPAuctionHouse implements AuctionHouse {\n  private static final String LOGGER_NAME = \"auction-sniper\";\n  public static final String LOG_FILE_NAME = \"auction-sniper.log\";\n  public static final String ITEM_ID_AS_LOGIN = \"auction-%s\"; \n  public static final String AUCTION_ID_FORMAT = ITEM_ID_AS_LOGIN + \"@%s/\" + XMPPAuctionHouse.AUCTION_RESOURCE;\n  public static final String AUCTION_RESOURCE = \"Auction\";\n  \n  private final XMPPConnection connection;\n  private final LoggingXMPPFailureReporter failureReporter;\n  \n  public XMPPAuctionHouse(XMPPConnection connection) throws XMPPAuctionException {\n    this.connection = connection;\n    this.failureReporter = new LoggingXMPPFailureReporter(makeLogger());\n  }\n\n  public Auction auctionFor(Item item) {\n    return new XMPPAuction(connection, auctionId(item.identifier, connection), failureReporter);\n  }\n\n  public void disconnect() {\n    connection.disconnect();\n  }\n\n  public static XMPPAuctionHouse connect(String hostname, String username, String password) throws XMPPAuctionException {\n    XMPPConnection connection = new XMPPConnection(hostname); \n    try {\n      connection.connect(); \n      connection.login(username, password, AUCTION_RESOURCE); \n      return new XMPPAuctionHouse(connection);\n    } catch (XMPPException xmppe) {\n        throw new XMPPAuctionException(\"Could not connect to auction: \" + connection, xmppe);\n    }\n  }\n  \n  private static String auctionId(String itemId, XMPPConnection connection) { \n    return String.format(AUCTION_ID_FORMAT, itemId, connection.getServiceName());\n  }\n  \n  private Logger makeLogger() throws XMPPAuctionException { \n    Logger logger = Logger.getLogger(LOGGER_NAME); \n    logger.setUseParentHandlers(false); \n    logger.addHandler(simpleFileHandler()); \n    return logger; \n  }\n  \n  private FileHandler simpleFileHandler() throws XMPPAuctionException { \n    try { \n      FileHandler handler = new FileHandler(LOG_FILE_NAME); \n      handler.setFormatter(new SimpleFormatter()); \n      return handler; \n    } catch (Exception e) { \n      throw new XMPPAuctionException(\"Could not create logger FileHandler \" \n                                   + FilenameUtils.getFullPath(LOG_FILE_NAME), e); \n    } \n  } \n\n}\n"
  },
  {
    "path": "src/auctionsniper/xmpp/XMPPFailureReporter.java",
    "content": "package auctionsniper.xmpp;\n\npublic interface XMPPFailureReporter { \n  void cannotTranslateMessage(String auctionId, String failedMessage, Exception exception);\n}"
  },
  {
    "path": "test/end-to-end/test/endtoend/auctionsniper/ApplicationRunner.java",
    "content": "package test.endtoend.auctionsniper;\n\nimport static auctionsniper.ui.SnipersTableModel.textFor;\nimport static org.hamcrest.Matchers.containsString;\nimport static test.endtoend.auctionsniper.FakeAuctionServer.XMPP_HOSTNAME;\n\nimport java.io.IOException;\n\nimport javax.swing.SwingUtilities;\n\nimport auctionsniper.Main;\nimport auctionsniper.SniperState;\nimport auctionsniper.ui.MainWindow;\n\npublic class ApplicationRunner { \n  public static final String SNIPER_ID = \"sniper\"; \n  public static final String SNIPER_PASSWORD = \"sniper\";\n  public static final String SNIPER_XMPP_ID = SNIPER_ID + \"@\" + XMPP_HOSTNAME + \"/Auction\";\n\n  private AuctionLogDriver logDriver = new AuctionLogDriver();\n  private AuctionSniperDriver driver; \n  \n  public void startBiddingIn(final FakeAuctionServer... auctions) {\n    startSniper(); \n    for (FakeAuctionServer auction : auctions) {\n      openBiddingFor(auction, Integer.MAX_VALUE);\n    }\n  }\n  public void startBiddingWithStopPrice(FakeAuctionServer auction, int stopPrice) {\n    startSniper();\n    openBiddingFor(auction, stopPrice);\n  }  \n\n  public void hasShownSniperHasLostAuction(FakeAuctionServer auction, int lastPrice, int lastBid) {\n    driver.showsSniperStatus(auction.getItemId(), lastPrice, lastBid, textFor(SniperState.LOST));\n  } \n  \n  public void hasShownSniperIsBidding(FakeAuctionServer auction, int lastPrice, int lastBid) {\n    driver.showsSniperStatus(auction.getItemId(), lastPrice, lastBid, textFor(SniperState.BIDDING));\n  }\n\n  public void hasShownSniperIsWinning(FakeAuctionServer auction, int winningBid) {\n    driver.showsSniperStatus(auction.getItemId(), winningBid, winningBid, textFor(SniperState.WINNING));\n  }\n\n  public void hasShownSniperIsLosing(FakeAuctionServer auction, int lastPrice, int lastBid) {\n    driver.showsSniperStatus(auction.getItemId(), lastPrice, lastBid, textFor(SniperState.LOSING));\n  }\n\n  public void hasShownSniperHasWonAuction(FakeAuctionServer auction, int lastPrice) {\n    driver.showsSniperStatus(auction.getItemId(), lastPrice, lastPrice, textFor(SniperState.WON));\n  }\n\n  public void hasShownSniperHasFailed(FakeAuctionServer auction) {\n    driver.showsSniperStatus(auction.getItemId(), 0, 0, textFor(SniperState.FAILED));\n  }\n\n  public void reportsInvalidMessage(FakeAuctionServer auction, String brokenMessage) throws IOException {\n    logDriver.hasEntry(containsString(brokenMessage));\n  }\n\n  public void stop() { \n    if (driver != null) { \n      driver.dispose();  \n    } \n  }\n\n  private void startSniper() {\n    logDriver.clearLog();\n    Thread thread = new Thread(\"Test Application\") { \n      @Override public void run() {  \n        try { \n          Main.main(XMPP_HOSTNAME, SNIPER_ID, SNIPER_PASSWORD);\n        } catch (Exception e) { \n          e.printStackTrace();  \n        } \n      } \n    }; \n    thread.setDaemon(true); \n    thread.start(); \n    makeSureAwtIsLoadedBeforeStartingTheDriverOnOSXToStopDeadlock();\n    \n    driver = new AuctionSniperDriver(1000);  \n    driver.hasTitle(MainWindow.APPLICATION_TITLE); \n    driver.hasColumnTitles();\n  } \n\n  private void openBiddingFor(FakeAuctionServer auction, int stopPrice) {\n    final String itemId = auction.getItemId();\n    driver.startBiddingWithStopPrice(itemId, stopPrice);\n    driver.showsSniperStatus(itemId, 0, 0, textFor(SniperState.JOINING));\n  }\n\n  private void makeSureAwtIsLoadedBeforeStartingTheDriverOnOSXToStopDeadlock() {\n    try {\n      SwingUtilities.invokeAndWait(new Runnable() { public void run() {} });\n    } catch (Exception e) {\n      throw new AssertionError(e);\n    }\n  }\n} \n"
  },
  {
    "path": "test/end-to-end/test/endtoend/auctionsniper/AuctionLogDriver.java",
    "content": "package test.endtoend.auctionsniper;\n\nimport static org.junit.Assert.assertThat;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.logging.LogManager;\n\nimport org.apache.commons.io.FileUtils;\nimport org.hamcrest.Matcher;\n\nimport auctionsniper.xmpp.XMPPAuctionHouse;\n\npublic class AuctionLogDriver { \n  private final File logFile = new File(XMPPAuctionHouse.LOG_FILE_NAME); \n\n  public void hasEntry(Matcher<String> matcher) throws IOException  { \n    assertThat(FileUtils.readFileToString(logFile), matcher); \n  } \n\n  public void clearLog() {\n    logFile.delete();\n    LogManager.getLogManager().reset(); \n  } \n} \n"
  },
  {
    "path": "test/end-to-end/test/endtoend/auctionsniper/AuctionSniperDriver.java",
    "content": "package test.endtoend.auctionsniper;\n\nimport static auctionsniper.ui.MainWindow.NEW_ITEM_ID_NAME;\nimport static auctionsniper.ui.MainWindow.NEW_ITEM_STOP_PRICE_NAME;\nimport static com.objogate.wl.swing.matcher.IterableComponentsMatcher.matching;\nimport static com.objogate.wl.swing.matcher.JLabelTextMatcher.withLabelText;\nimport static java.lang.String.valueOf;\n\nimport javax.swing.JButton;\nimport javax.swing.JTextField;\nimport javax.swing.table.JTableHeader;\n\nimport auctionsniper.ui.MainWindow;\n\nimport com.objogate.wl.swing.AWTEventQueueProber;\nimport com.objogate.wl.swing.driver.JButtonDriver;\nimport com.objogate.wl.swing.driver.JFrameDriver;\nimport com.objogate.wl.swing.driver.JTableDriver;\nimport com.objogate.wl.swing.driver.JTableHeaderDriver;\nimport com.objogate.wl.swing.driver.JTextFieldDriver;\nimport com.objogate.wl.swing.gesture.GesturePerformer;\n\n@SuppressWarnings(\"unchecked\")\npublic class AuctionSniperDriver extends JFrameDriver { \n  public AuctionSniperDriver(int timeoutMillis) { \n    super(new GesturePerformer(), \n          JFrameDriver.topLevelFrame( \n            named(MainWindow.MAIN_WINDOW_NAME), \n            showingOnScreen()), \n            new AWTEventQueueProber(timeoutMillis, 100)); \n  }\n  \n  public void hasColumnTitles() { \n    JTableHeaderDriver headers = new JTableHeaderDriver(this, \n                                                        JTableHeader.class); \n    headers.hasHeaders( \n       matching(withLabelText(\"Item\"), withLabelText(\"Last Price\"), \n                withLabelText(\"Last Bid\"), withLabelText(\"State\"))); \n  } \n\n  public void showsSniperStatus(String itemId, int lastPrice, int lastBid, String statusText) {\n    JTableDriver table = new JTableDriver(this); \n    table.hasRow( \n        matching(withLabelText(itemId), withLabelText(valueOf(lastPrice)), \n               withLabelText(valueOf(lastBid)), withLabelText(statusText)));     \n  }\n\n  public void startBiddingWithStopPrice(String itemId, int stopPrice) {\n    textField(NEW_ITEM_ID_NAME).replaceAllText(itemId); \n    textField(NEW_ITEM_STOP_PRICE_NAME).replaceAllText(String.valueOf(stopPrice)); \n    bidButton().click(); \n  }\n\n  private JTextFieldDriver textField(String fieldName) {\n    JTextFieldDriver newItemId = \n      new JTextFieldDriver(this, JTextField.class, named(fieldName));\n    newItemId.focusWithMouse();\n    return newItemId;\n  }\n\n  private JButtonDriver bidButton() {\n    return new JButtonDriver(this, JButton.class, named(MainWindow.JOIN_BUTTON_NAME));\n  } \n} \n"
  },
  {
    "path": "test/end-to-end/test/endtoend/auctionsniper/AuctionSniperEndToEndTest.java",
    "content": "package test.endtoend.auctionsniper;\n\nimport org.junit.After;\nimport org.junit.Test;\n\npublic class AuctionSniperEndToEndTest { \n  private final FakeAuctionServer auction = new FakeAuctionServer(\"item-54321\");\n  private final FakeAuctionServer auction2 = new FakeAuctionServer(\"item-65432\");  \n\n  private final ApplicationRunner application = new ApplicationRunner(); \n  \n  @Test public void \n  sniperJoinsAuctionUntilAuctionCloses() throws Exception { \n    auction.startSellingItem();                \n    application.startBiddingIn(auction);       \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auction.announceClosed();                  \n    application.hasShownSniperHasLostAuction(auction, 0, 0);   \n  } \n\n  \n  @Test public void \n  sniperMakesAHigherBidButLoses() throws Exception { \n    auction.startSellingItem(); \n    \n    application.startBiddingIn(auction); \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID);\n    auction.reportPrice(1000, 98, \"other bidder\");  \n    application.hasShownSniperIsBidding(auction, 1000, 1098); \n    \n    auction.hasReceivedBid(1098, ApplicationRunner.SNIPER_XMPP_ID);\n\n    auction.announceClosed();                  \n    application.hasShownSniperHasLostAuction(auction, 1000, 1098);   \n  } \n  \n  @Test public void \n  sniperWinsAnAuctionByBiddingHigher() throws Exception { \n    auction.startSellingItem(); \n    \n    application.startBiddingIn(auction); \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auction.reportPrice(1000, 98, \"other bidder\"); \n    application.hasShownSniperIsBidding(auction, 1000, 1098); \n    \n    auction.hasReceivedBid(1098, ApplicationRunner.SNIPER_XMPP_ID); \n    \n    auction.reportPrice(1098, 97, ApplicationRunner.SNIPER_XMPP_ID); \n    application.hasShownSniperIsWinning(auction, 1098); \n    \n    auction.announceClosed(); \n    application.hasShownSniperHasWonAuction(auction, 1098); \n  } \n\n  @Test public void \n  sniperBidsForMultipleItems() throws Exception { \n    auction.startSellingItem(); \n    auction2.startSellingItem(); \n    \n    application.startBiddingIn(auction, auction2); \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auction2.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    \n    auction.reportPrice(1000, 98, \"other bidder\"); \n    auction.hasReceivedBid(1098, ApplicationRunner.SNIPER_XMPP_ID);\n    \n    auction2.reportPrice(500, 21, \"other bidder\"); \n    auction2.hasReceivedBid(521, ApplicationRunner.SNIPER_XMPP_ID);\n    \n    auction.reportPrice(1098, 97, ApplicationRunner.SNIPER_XMPP_ID);    \n    auction2.reportPrice(521, 22, ApplicationRunner.SNIPER_XMPP_ID); \n    \n    application.hasShownSniperIsWinning(auction, 1098); \n    application.hasShownSniperIsWinning(auction2, 521);\n    \n    auction.announceClosed(); \n    auction2.announceClosed();\n    \n    application.hasShownSniperHasWonAuction(auction, 1098); \n    application.hasShownSniperHasWonAuction(auction2, 521); \n  } \n\n  @Test public void \n  sniperLosesAnAuctionWhenThePriceIsTooHigh() throws Exception { \n    auction.startSellingItem(); \n    \n    application.startBiddingWithStopPrice(auction, 1100); \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auction.reportPrice(1000, 98, \"other bidder\"); \n    application.hasShownSniperIsBidding(auction, 1000, 1098);\n    \n    auction.hasReceivedBid(1098, ApplicationRunner.SNIPER_XMPP_ID); \n    \n    auction.reportPrice(1197, 10, \"third party\"); \n    application.hasShownSniperIsLosing(auction, 1197, 1098); \n    \n    auction.reportPrice(1207, 10, \"fourth party\"); \n    application.hasShownSniperIsLosing(auction, 1207, 1098); \n    auction.announceClosed(); \n    application.hasShownSniperHasLostAuction(auction, 1207, 1098); \n  } \n\n  @Test public void \n  sniperReportsInvalidAuctionMessageAndStopsRespondingToEvents() \n      throws Exception \n  { \n    String brokenMessage = \"a broken message\"; \n    auction.startSellingItem(); \n    auction2.startSellingItem();\n    \n    application.startBiddingIn(auction, auction2); \n    auction.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID);\n    \n    auction.reportPrice(500, 20, \"other bidder\"); \n    auction.hasReceivedBid(520, ApplicationRunner.SNIPER_XMPP_ID);\n    \n    auction.sendInvalidMessageContaining(brokenMessage); \n    application.hasShownSniperHasFailed(auction); \n    \n    auction.reportPrice(520, 21, \"other bidder\"); \n    waitForAnotherAuctionEvent(); \n    \n    application.reportsInvalidMessage(auction, brokenMessage); \n    application.hasShownSniperHasFailed(auction); \n  } \n  \n  private void waitForAnotherAuctionEvent() throws Exception { \n    auction2.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auction2.reportPrice(600, 6, \"other bidder\"); \n    application.hasShownSniperIsBidding(auction2, 600, 606); \n  } \n\n  @After public void stopAuction() { \n    auction.stop(); \n    auction2.stop();\n  } \n  @After public void stopApplication() { \n    application.stop(); \n  } \n} \n"
  },
  {
    "path": "test/end-to-end/test/endtoend/auctionsniper/FakeAuctionServer.java",
    "content": "package test.endtoend.auctionsniper;\n\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasProperty;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.notNullValue;\nimport static org.junit.Assert.assertThat;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.hamcrest.Matcher;\nimport org.jivesoftware.smack.Chat;\nimport org.jivesoftware.smack.ChatManagerListener;\nimport org.jivesoftware.smack.MessageListener;\nimport org.jivesoftware.smack.XMPPConnection;\nimport org.jivesoftware.smack.XMPPException;\nimport org.jivesoftware.smack.packet.Message;\n\nimport auctionsniper.xmpp.XMPPAuction;\n\npublic class FakeAuctionServer {\n  public static final String ITEM_ID_AS_LOGIN = \"auction-%s\";\n  public static final String AUCTION_RESOURCE = \"Auction\";\n  public static final String XMPP_HOSTNAME = \"localhost\";\n\n  private static final String AUCTION_PASSWORD = \"auction\";\n  private final SingleMessageListener messageListener = new SingleMessageListener();\n  private final String itemId;\n  private final XMPPConnection connection;\n\n  private Chat currentChat;\n\n  public FakeAuctionServer(String itemId) {\n    this.itemId = itemId;\n    this.connection = new XMPPConnection(XMPP_HOSTNAME);\n  }\n\n  public void startSellingItem() throws XMPPException {\n    connection.connect();\n    connection.login(String.format(ITEM_ID_AS_LOGIN, itemId), AUCTION_PASSWORD,\n        AUCTION_RESOURCE);\n    connection.getChatManager().addChatListener(new ChatManagerListener() {\n      public void chatCreated(Chat chat, boolean createdLocally) {\n        currentChat = chat;\n        chat.addMessageListener(messageListener);\n      }\n    });\n  }\n\n  public void sendInvalidMessageContaining(String brokenMessage) throws XMPPException {\n    currentChat.sendMessage(brokenMessage);\n  } \n\n  public void reportPrice(int price, int increment, String bidder) throws XMPPException {\n  currentChat.sendMessage( \n      String.format(\"SOLVersion: 1.1; Event: PRICE; \" \n                    + \"CurrentPrice: %d; Increment: %d; Bidder: %s;\", \n                    price, increment, bidder)); \n  }\n  \n  public void hasReceivedJoinRequestFrom(String sniperId) throws InterruptedException {\n    receivesAMessageMatching(sniperId, equalTo(XMPPAuction.JOIN_COMMAND_FORMAT)); \n  } \n  public void hasReceivedBid(int bid, String sniperId) throws InterruptedException {\n    receivesAMessageMatching(sniperId, \n                           equalTo(String.format(XMPPAuction.BID_COMMAND_FORMAT, bid))); \n  } \n  \n  private void receivesAMessageMatching(String sniperId, Matcher<? super String> messageMatcher) throws InterruptedException {\n    messageListener.receivesAMessage(messageMatcher); \n    assertThat(currentChat.getParticipant(), equalTo(sniperId)); \n  } \n  \n  public void announceClosed() throws XMPPException { \n    currentChat.sendMessage(\"SOLVersion: 1.1; Event: CLOSE;\"); \n  } \n\n  public void stop() { \n    connection.disconnect(); \n  } \n\n  public String getItemId() {\n    return itemId;\n  }\n  \n  public class SingleMessageListener implements MessageListener { \n    private final ArrayBlockingQueue<Message> messages = \n                                new ArrayBlockingQueue<Message>(1); \n    public void processMessage(Chat chat, Message message) { \n      messages.add(message); \n    } \n    public void receivesAMessage() throws InterruptedException { \n      assertThat(\"Message\", messages.poll(5, TimeUnit.SECONDS), is(notNullValue()));\n    } \n\n    public void receivesAMessage(Matcher<? super String> messageMatcher) \n      throws InterruptedException \n    { \n      final Message message = messages.poll(5, TimeUnit.SECONDS); \n      assertThat(message, hasProperty(\"body\", messageMatcher));\n    } \n  }\n\n}\n"
  },
  {
    "path": "test/integration/test/integration/auctionsniper/ui/MainWindowTest.java",
    "content": "package test.integration.auctionsniper.ui;\n\nimport static org.hamcrest.Matchers.equalTo;\n\nimport org.junit.Test;\n\nimport test.endtoend.auctionsniper.AuctionSniperDriver;\nimport auctionsniper.UserRequestListener;\nimport auctionsniper.SniperPortfolio;\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.ui.MainWindow;\n\nimport com.objogate.wl.swing.probe.ValueMatcherProbe;\n\npublic class MainWindowTest {\n  private final MainWindow mainWindow = new MainWindow(new SniperPortfolio()); \n  private final AuctionSniperDriver driver = new AuctionSniperDriver(100); \n  \n  @Test public void \n  makesUserRequestWhenJoinButtonClicked() { \n    final ValueMatcherProbe<Item> itemProbe = \n      new ValueMatcherProbe<Item>(equalTo(new Item(\"an item-id\", 789)), \n                                  \"item request\");\n    mainWindow.addUserRequestListener( \n        new UserRequestListener() { \n          public void joinAuction(Item item) { \n            itemProbe.setReceivedValue(item); \n          } \n        }); \n    \n    driver.startBiddingWithStopPrice(\"an item-id\", 789);\n    driver.check(itemProbe); \n  }\n}\n"
  },
  {
    "path": "test/integration/test/integration/auctionsniper/xmpp/XMPPAuctionHouseTest.java",
    "content": "package test.integration.auctionsniper.xmpp;\n\nimport static java.util.concurrent.TimeUnit.SECONDS;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.jivesoftware.smack.XMPPException;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport test.endtoend.auctionsniper.ApplicationRunner;\nimport test.endtoend.auctionsniper.FakeAuctionServer;\nimport auctionsniper.Auction;\nimport auctionsniper.AuctionEventListener;\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.xmpp.XMPPAuctionException;\nimport auctionsniper.xmpp.XMPPAuctionHouse;\n\npublic class XMPPAuctionHouseTest {\n  private final FakeAuctionServer auctionServer = new FakeAuctionServer(\"item-54321\");  \n  private XMPPAuctionHouse auctionHouse; \n\n  @Before public void openConnection() throws XMPPAuctionException {\n    auctionHouse = XMPPAuctionHouse.connect(FakeAuctionServer.XMPP_HOSTNAME, ApplicationRunner.SNIPER_ID, ApplicationRunner.SNIPER_PASSWORD);\n    \n  }\n  @After public void closeConnection() {\n    if (auctionHouse != null) {\n      auctionHouse.disconnect();\n    }\n  }\n  @Before public void startAuction() throws XMPPException {\n    auctionServer.startSellingItem();\n  }\n  @After public void stopAuction() {\n    auctionServer.stop();\n  }\n\n\n  @Test public void \n  receivesEventsFromAuctionServerAfterJoining() throws Exception { \n    CountDownLatch auctionWasClosed = new CountDownLatch(1); \n    \n    Auction auction = auctionHouse.auctionFor(new Item(auctionServer.getItemId(), 567));\n    auction.addAuctionEventListener(auctionClosedListener(auctionWasClosed));\n    auction.join(); \n    auctionServer.hasReceivedJoinRequestFrom(ApplicationRunner.SNIPER_XMPP_ID); \n    auctionServer.announceClosed(); \n    \n    assertTrue(\"should have been closed\", auctionWasClosed.await(4, SECONDS)); \n  } \n\n  private AuctionEventListener \n  auctionClosedListener(final CountDownLatch auctionWasClosed) { \n    return new AuctionEventListener() { \n      public void auctionClosed() { \n        auctionWasClosed.countDown(); \n      } \n      public void currentPrice(int price, int increment, PriceSource priceSource) { }\n      public void auctionFailed() { }\n    }; \n  }\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/AuctionSniperTest.java",
    "content": "package test.auctionsniper;\n\nimport static auctionsniper.SniperState.BIDDING;\nimport static auctionsniper.SniperState.LOSING;\nimport static auctionsniper.SniperState.LOST;\nimport static auctionsniper.SniperState.WINNING;\nimport static auctionsniper.SniperState.WON;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.samePropertyValuesAs;\nimport static org.junit.Assert.assertThat;\n\nimport org.hamcrest.FeatureMatcher;\nimport org.hamcrest.Matcher;\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.Sequence;\nimport org.jmock.States;\nimport org.jmock.integration.junit4.JMock;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.Auction;\nimport auctionsniper.AuctionSniper;\nimport auctionsniper.SniperListener;\nimport auctionsniper.SniperSnapshot;\nimport auctionsniper.SniperState;\nimport auctionsniper.AuctionEventListener.PriceSource;\nimport auctionsniper.UserRequestListener.Item;\n\n@RunWith(JMock.class) \npublic class AuctionSniperTest { \n  protected static final String ITEM_ID = \"item-id\";\n  public static final Item ITEM = new Item(ITEM_ID, 1234);\n  private final Mockery context = new Mockery(); \n  private final States sniperState = context.states(\"sniper\");\n  private final Auction auction = context.mock(Auction.class);\n  private final SniperListener sniperListener = context.mock(SniperListener.class);\n  private final AuctionSniper sniper = new AuctionSniper(ITEM, auction); \n  \n  @Before public void attachListener() {\n    sniper.addSniperListener(sniperListener);\n  }\n  \n  @Test public void\n  hasInitialStateOfJoining() {\n    assertThat(sniper.getSnapshot(), samePropertyValuesAs(SniperSnapshot.joining(ITEM_ID)));\n  }\n  \n  @Test public void \n  reportsLostWhenAuctionClosesImmediately() { \n    context.checking(new Expectations() {{ \n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, 0, 0, LOST));  \n    }}); \n    \n    sniper.auctionClosed(); \n  }\n  \n  @Test public void \n  bidsHigherAndReportsBiddingWhenNewPriceArrives() { \n    final int price = 1001; \n    final int increment = 25; \n    final int bid = price + increment;\n    context.checking(new Expectations() {{ \n      one(auction).bid(bid); \n      \n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, price, bid, BIDDING)); \n    }}); \n    \n    sniper.currentPrice(price, increment, PriceSource.FromOtherBidder); \n  } \n  \n\n  @Test public void\n  doesNotBidAndReportsLosingIfFirstPriceIsAboveStopPrice() {\n    final int price = 1233;\n    final int increment = 25;\n\n    context.checking(new Expectations() {{\n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, price, 0, LOSING));\n    }});\n    \n    sniper.currentPrice(price, increment, PriceSource.FromOtherBidder);\n  }\n\n  @Test public void\n  doesNotBidAndReportsLosingIfSubsequentPriceIsAboveStopPrice() {\n    allowingSniperBidding();\n    context.checking(new Expectations() {{\n      int bid = 123 + 45;\n      allowing(auction).bid(bid);\n      \n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, 2345, bid, LOSING)); when(sniperState.is(\"bidding\"));\n    }});\n   \n    sniper.currentPrice(123, 45, PriceSource.FromOtherBidder);\n    sniper.currentPrice(2345, 25, PriceSource.FromOtherBidder);\n  }\n  \n  @Test public void\n  doesNotBidAndReportsLosingIfPriceAfterWinningIsAboveStopPrice() {\n    final int price = 1233;\n    final int increment = 25;\n\n    allowingSniperBidding();\n    allowingSniperWinning();\n    context.checking(new Expectations() {{\n      int bid = 123 + 45;\n      allowing(auction).bid(bid);\n      \n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, price, bid, LOSING)); when(sniperState.is(\"winning\"));\n    }});\n   \n    sniper.currentPrice(123, 45, PriceSource.FromOtherBidder);\n    sniper.currentPrice(168, 45, PriceSource.FromSniper);\n    sniper.currentPrice(price, increment, PriceSource.FromOtherBidder);\n  }\n\n  @Test public void\n  continuesToBeLosingOnceStopPriceHasBeenReached() {\n    final Sequence states = context.sequence(\"sniper states\");\n    final int price1 = 1233;\n    final int price2 = 1258;\n\n    context.checking(new Expectations() {{\n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, price1, 0, LOSING)); inSequence(states);\n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, price2, 0, LOSING)); inSequence(states);\n    }});\n   \n    sniper.currentPrice(price1, 25, PriceSource.FromOtherBidder);\n    sniper.currentPrice(price2, 25, PriceSource.FromOtherBidder);\n  }\n\n  @Test public void \n  reportsLostIfAuctionClosesWhenBidding() { \n    allowingSniperBidding();\n    ignoringAuction();\n    \n    context.checking(new Expectations() {{ \n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, 123, 168, LOST)); \n                                                                    when(sniperState.is(\"bidding\")); \n    }}); \n    \n    sniper.currentPrice(123, 45, PriceSource.FromOtherBidder); \n    sniper.auctionClosed(); \n  } \n  \n  @Test public void\n  reportsLostIfAuctionClosesWhenLosing() {\n    allowingSniperLosing();\n    context.checking(new Expectations() {{\n      atLeast(1).of(sniperListener).sniperStateChanged(new SniperSnapshot(ITEM_ID, 1230, 0, LOST)); \n                                                                    when(sniperState.is(\"losing\"));\n    }});\n    \n    sniper.currentPrice(1230, 456, PriceSource.FromOtherBidder);\n    sniper.auctionClosed();\n  }\n\n\n\n  @Test public void \n  reportsIsWinningWhenCurrentPriceComesFromSniper() { \n    allowingSniperBidding();\n    ignoringAuction();\n    context.checking(new Expectations() {{ \n      atLeast(1).of(sniperListener).sniperStateChanged( new SniperSnapshot(ITEM_ID, 135, 135, WINNING)); when(sniperState.is(\"bidding\"));\n    }}); \n    \n    sniper.currentPrice(123, 12, PriceSource.FromOtherBidder);\n    sniper.currentPrice(135, 45, PriceSource.FromSniper); \n  } \n  \n  @Test public void \n  reportsWonIfAuctionClosesWhenWinning() { \n    allowingSniperBidding();\n    allowingSniperWinning();\n    ignoringAuction();\n    \n    context.checking(new Expectations() {{ \n      atLeast(1).of(sniperListener).sniperStateChanged( new SniperSnapshot(ITEM_ID, 135, 135, WON)); when(sniperState.is(\"winning\"));\n    }}); \n    \n    sniper.currentPrice(123, 12, PriceSource.FromOtherBidder);\n    sniper.currentPrice(135, 45, PriceSource.FromSniper); \n    sniper.auctionClosed(); \n  } \n\n  @Test public void \n  reportsFailedIfAuctionFailsWhenBidding() { \n    ignoringAuction();\n    allowingSniperBidding();\n    \n    expectSniperToFailWhenItIs(\"bidding\");\n    \n    sniper.currentPrice(123, 45, PriceSource.FromOtherBidder); \n    sniper.auctionFailed(); \n  } \n  \n  @Test public void\n  reportsFailedIfAuctionFailsImmediately() {\n    context.checking(new Expectations() {{\n      atLeast(1).of(sniperListener).sniperStateChanged(SniperSnapshot.joining(ITEM_ID).failed());\n    }});\n    \n    sniper.auctionFailed();\n  }\n\n  @Test public void\n  reportsFailedIfAuctionFailsWhenLosing() {\n    allowingSniperLosing();\n\n    expectSniperToFailWhenItIs(\"losing\");\n    \n    sniper.currentPrice(1230, 456, PriceSource.FromOtherBidder);\n    sniper.auctionFailed();\n  }\n\n\n  @Test public void\n  reportsFailedIfAuctionFailsWhenWinning() {\n    ignoringAuction();\n    allowingSniperBidding();\n    allowingSniperWinning();\n    \n    expectSniperToFailWhenItIs(\"winning\");\n    \n    sniper.currentPrice(123, 12, PriceSource.FromOtherBidder);\n    sniper.currentPrice(135, 45, PriceSource.FromSniper);\n    sniper.auctionFailed();\n  }\n\n\n  private void expectSniperToFailWhenItIs(final String state) {\n    context.checking(new Expectations() {{\n      atLeast(1).of(sniperListener).sniperStateChanged(\n          new SniperSnapshot(ITEM_ID, 00, 0, SniperState.FAILED)); \n                                      when(sniperState.is(state));\n    }});\n  }\n  private void ignoringAuction() {\n    context.checking(new Expectations() {{ \n      ignoring(auction);\n    }});\n  }\n  private void allowingSniperBidding() {\n    allowSniperStateChange(BIDDING, \"bidding\");\n  }\n\n  private void allowingSniperLosing() {\n    allowSniperStateChange(LOSING, \"losing\");\n  }\n\n  private void allowingSniperWinning() {\n    allowSniperStateChange(WINNING, \"winning\");\n  }\n\n  private void allowSniperStateChange(final SniperState newState, final String oldState) {\n    context.checking(new Expectations() {{ \n      allowing(sniperListener).sniperStateChanged(with(aSniperThatIs(newState))); then(sniperState.is(oldState));\n    }});\n  }\n\n  private Matcher<SniperSnapshot> aSniperThatIs(final SniperState state) { \n    return new FeatureMatcher<SniperSnapshot, SniperState>( equalTo(state), \"sniper that is \", \"was\") {\n      @Override \n      protected SniperState featureValueOf(SniperSnapshot actual) { \n        return actual.state; \n      } \n    }; \n  } \n} \n"
  },
  {
    "path": "test/unit/test/auctionsniper/SniperLauncherTest.java",
    "content": "package test.auctionsniper;\n\nimport static org.hamcrest.Matchers.equalTo;\n\nimport org.hamcrest.FeatureMatcher;\nimport org.hamcrest.Matcher;\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.States;\nimport org.jmock.integration.junit4.JMock;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.Auction;\nimport auctionsniper.AuctionHouse;\nimport auctionsniper.AuctionSniper;\nimport auctionsniper.SniperCollector;\nimport auctionsniper.SniperLauncher;\nimport auctionsniper.UserRequestListener.Item;\n\n@RunWith(JMock.class)\npublic class SniperLauncherTest {\n  private final Mockery context = new Mockery();\n  private final States auctionState = context.states(\"auction state\").startsAs(\"not joined\");\n  private final Auction auction = context.mock(Auction.class);\n  private final AuctionHouse auctionHouse = context.mock(AuctionHouse.class);\n  private final SniperCollector sniperCollector = context.mock(SniperCollector.class);\n  private final SniperLauncher launcher = new SniperLauncher(auctionHouse, sniperCollector);\n  \n  @Test public void\n  addsNewSniperToCollectorAndThenJoinsAuction() {\n    final Item item = new Item(\"item 123\", 456);\n\n    context.checking(new Expectations() {{\n      allowing(auctionHouse).auctionFor(item); will(returnValue(auction));\n      \n      oneOf(auction).addAuctionEventListener(with(sniperForItem(item))); when(auctionState.is(\"not joined\"));\n      oneOf(sniperCollector).addSniper(with(sniperForItem(item))); when(auctionState.is(\"not joined\"));\n      \n      one(auction).join(); then(auctionState.is(\"joined\"));\n    }});\n    \n    launcher.joinAuction(item);\n  }\n\n  protected Matcher<AuctionSniper>sniperForItem(Item item) {\n    return new FeatureMatcher<AuctionSniper, String>(equalTo(item.identifier), \"sniper with item id\", \"item\") {\n      @Override protected String featureValueOf(AuctionSniper actual) {\n        return actual.getSnapshot().itemId;\n      }\n    };\n  }\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/SniperPortfolioTest.java",
    "content": "package test.auctionsniper;\n\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.integration.junit4.JMock;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.AuctionSniper;\nimport auctionsniper.SniperPortfolio;\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.SniperPortfolio.PortfolioListener;\n\n@RunWith(JMock.class)\npublic class SniperPortfolioTest {\n  private final Mockery context = new Mockery();\n  private final PortfolioListener listener = context.mock(PortfolioListener.class);\n  private final SniperPortfolio portfolio = new SniperPortfolio();\n  \n  @Test public void\n  notifiesListenersOfNewSnipers() {\n    final AuctionSniper sniper = new AuctionSniper(new Item(\"item id\", 123), null);\n    context.checking(new Expectations() {{\n      oneOf(listener).sniperAdded(sniper);\n    }});\n    portfolio.addPortfolioListener(listener);\n    \n    portfolio.addSniper(sniper);\n  }\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/SniperSnapshotTest.java",
    "content": "package test.auctionsniper;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.Test;\n\nimport auctionsniper.SniperSnapshot;\nimport auctionsniper.SniperState;\n\npublic class SniperSnapshotTest {\n\n  @Test public void\n  transitionsBetweenStates() {\n    final String itemId = \"item id\";\n    SniperSnapshot joining = SniperSnapshot.joining(itemId);\n    \n    assertEquals(new SniperSnapshot(itemId, 0, 0, SniperState.JOINING),\n        joining);\n    \n    SniperSnapshot bidding = joining.bidding(123, 234);\n    assertEquals(\n        new SniperSnapshot(itemId, 123, 234, SniperState.BIDDING),\n        bidding);  \n\n    assertEquals(new SniperSnapshot(itemId, 456, 234, SniperState.LOSING),\n                 bidding.losing(456));\n    \n    assertEquals(\n        new SniperSnapshot(itemId, 456, 234, SniperState.WINNING),\n        bidding.winning(456));  \n\n    assertEquals(\n        new SniperSnapshot(itemId, 123, 234, SniperState.LOST),\n        bidding.closed());  \n\n    assertEquals(\n        new SniperSnapshot(itemId, 678, 234, SniperState.WON),\n        bidding.winning(678).closed());  \n  }\n  \n  @Test public void\n  comparesItemIdentities() {\n    assertTrue(\n        SniperSnapshot.joining(\"item 1\").isForSameItemAs(\n            SniperSnapshot.joining(\"item 1\")));\n    assertFalse(\n        SniperSnapshot.joining(\"item 1\").isForSameItemAs(\n            SniperSnapshot.joining(\"item 2\")));\n  }\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/SniperStateTests.java",
    "content": "package test.auctionsniper;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\nimport auctionsniper.SniperState;\nimport auctionsniper.util.Defect;\n\npublic class SniperStateTests {\n\n  @Test public void\n  isWonWhenAuctionClosesWhileWinning() {\n    assertEquals(SniperState.LOST, SniperState.JOINING.whenAuctionClosed());\n    assertEquals(SniperState.LOST, SniperState.BIDDING.whenAuctionClosed());\n    assertEquals(SniperState.WON, SniperState.WINNING.whenAuctionClosed());\n  }\n  \n  @Test(expected=Defect.class) public void\n  defectIfAuctionClosesWhenWon() {\n    SniperState.WON.whenAuctionClosed();\n  }\n\n  @Test(expected=Defect.class) public void\n  defectIfAuctionClosesWhenLost() {\n    SniperState.LOST.whenAuctionClosed();\n  }\n\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/ui/ColumnTest.java",
    "content": "package test.auctionsniper.ui;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\n\nimport auctionsniper.SniperSnapshot;\nimport auctionsniper.SniperState;\nimport auctionsniper.ui.Column;\n\npublic class ColumnTest {\n\n  @Test public void\n  retrievesValuesFromASniperSnapshot() {\n    SniperSnapshot snapshot = new SniperSnapshot(\"item\", 123, 34, SniperState.BIDDING);\n    assertEquals(\"item\", Column.ITEM_IDENTIFIER.valueIn(snapshot));\n    assertEquals(123, Column.LAST_PRICE.valueIn(snapshot));\n    assertEquals(34, Column.LAST_BID.valueIn(snapshot));\n    assertEquals(\"Bidding\", Column.SNIPER_STATE.valueIn(snapshot));\n  }\n}\n"
  },
  {
    "path": "test/unit/test/auctionsniper/ui/SnipersTableModelTest.java",
    "content": "package test.auctionsniper.ui;\n\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.hasProperty;\nimport static org.hamcrest.Matchers.samePropertyValuesAs;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertThat;\n\nimport javax.swing.event.TableModelEvent;\nimport javax.swing.event.TableModelListener;\n\nimport org.hamcrest.Matcher;\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.integration.junit4.JMock;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.AuctionSniper;\nimport auctionsniper.SniperSnapshot;\nimport auctionsniper.SniperState;\nimport auctionsniper.UserRequestListener.Item;\nimport auctionsniper.ui.Column;\nimport auctionsniper.ui.SnipersTableModel;\nimport auctionsniper.util.Defect;\n\n@RunWith(JMock.class) \npublic class SnipersTableModelTest { \n  private static final String ITEM_ID = \"item 0\";\n  private final Mockery context = new Mockery(); \n  private TableModelListener listener = context.mock(TableModelListener.class); \n  private final SnipersTableModel model = new SnipersTableModel();\n  private final AuctionSniper sniper = new AuctionSniper(new Item(ITEM_ID, 234), null); \n  \n  @Before public void attachModelListener() {\n    model.addTableModelListener(listener); \n  } \n  \n  @Test public void \n  hasEnoughColumns() { \n    assertThat(model.getColumnCount(), equalTo(Column.values().length)); \n  }\n  \n  @Test public void \n  setsUpColumnHeadings() { \n    for (Column column: Column.values()) { \n      assertEquals(column.name, model.getColumnName(column.ordinal())); \n    } \n  } \n  \n  @Test public void\n  acceptsNewSniper() {\n    context.checking(new Expectations() {{\n      one(listener).tableChanged(with(anInsertionAtRow(0)));\n    }});\n\n    model.sniperAdded(sniper);\n    \n    assertRowMatchesSnapshot(0, SniperSnapshot.joining(ITEM_ID));\n  }\n  \n  @Test public void \n  setsSniperValuesInColumns() { \n    SniperSnapshot bidding = sniper.getSnapshot().bidding(555, 666);\n    context.checking(new Expectations() {{ \n      allowing(listener).tableChanged(with(anyInsertionEvent()));\n      \n      one(listener).tableChanged(with(aChangeInRow(0))); \n    }}); \n\n    model.sniperAdded(sniper);\n    model.sniperStateChanged(bidding);\n    \n    assertRowMatchesSnapshot(0, bidding);\n  } \n  \n  @Test public void\n  notifiesListenersWhenAddingASniper() {\n    context.checking(new Expectations() { {\n      one(listener).tableChanged(with(anInsertionAtRow(0)));\n    }});\n\n    assertEquals(0, model.getRowCount());\n    \n    model.sniperAdded(sniper);\n    \n    assertEquals(1, model.getRowCount());\n    assertRowMatchesSnapshot(0, SniperSnapshot.joining(ITEM_ID));\n  }\n  \n  @Test public void \n  holdsSnipersInAdditionOrder() {\n    AuctionSniper sniper2 = new AuctionSniper(new Item(\"item 1\", 345), null);\n    context.checking(new Expectations() { {\n      ignoring(listener);\n    }});\n    \n    model.sniperAdded(sniper);\n    model.sniperAdded(sniper2);\n    \n    assertEquals(ITEM_ID, cellValue(0, Column.ITEM_IDENTIFIER));\n    assertEquals(\"item 1\", cellValue(1, Column.ITEM_IDENTIFIER));\n  }\n  \n  @Test public void \n  updatesCorrectRowForSniper() {\n    AuctionSniper sniper2 = new AuctionSniper(new Item(\"item 1\", 345), null);\n    context.checking(new Expectations() { {\n      allowing(listener).tableChanged(with(anyInsertionEvent()));\n\n      one(listener).tableChanged(with(aChangeInRow(1)));\n    }});\n    \n    model.sniperAdded(sniper);\n    model.sniperAdded(sniper2);\n\n    SniperSnapshot winning1 = sniper2.getSnapshot().winning(123);\n    model.sniperStateChanged(winning1);\n    \n    assertRowMatchesSnapshot(1, winning1);\n  }\n\n  @Test(expected=Defect.class) public void\n  throwsDefectIfNoExistingSniperForAnUpdate() {\n    model.sniperStateChanged(new SniperSnapshot(\"item 1\", 123, 234, SniperState.WINNING));\n  }\n  \n  private void assertRowMatchesSnapshot(int row, SniperSnapshot snapshot) {\n    assertEquals(snapshot.itemId, cellValue(row, Column.ITEM_IDENTIFIER));\n    assertEquals(snapshot.lastPrice, cellValue(row, Column.LAST_PRICE));\n    assertEquals(snapshot.lastBid, cellValue(row, Column.LAST_BID));\n    assertEquals(SnipersTableModel.textFor(snapshot.state), cellValue(row, Column.SNIPER_STATE));\n  }\n\n  private Object cellValue(int rowIndex, Column column) {\n    return model.getValueAt(rowIndex, column.ordinal());\n  }\n\n  Matcher<TableModelEvent> anyInsertionEvent() {\n    return hasProperty(\"type\", equalTo(TableModelEvent.INSERT));\n  }\n  Matcher<TableModelEvent> anInsertionAtRow(final int row) {\n    return samePropertyValuesAs(new TableModelEvent(model, row, row, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT));\n  }\n\n  private Matcher<TableModelEvent> aChangeInRow(int row) { \n    return samePropertyValuesAs(new TableModelEvent(model, row)); \n  } \n  \n} \n"
  },
  {
    "path": "test/unit/test/auctionsniper/xmpp/AuctionMessageTranslatorTest.java",
    "content": "package test.auctionsniper.xmpp;\n\nimport org.jivesoftware.smack.Chat;\nimport org.jivesoftware.smack.packet.Message;\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.integration.junit4.JMock;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.AuctionEventListener;\nimport auctionsniper.AuctionEventListener.PriceSource;\nimport auctionsniper.xmpp.AuctionMessageTranslator;\nimport auctionsniper.xmpp.XMPPFailureReporter;\n\n@RunWith(JMock.class) \npublic class AuctionMessageTranslatorTest { \n  private static final String SNIPER_ID = \"sniper id\";\n  private static final Chat UNUSED_CHAT = null;\n  \n  private final Mockery context = new Mockery(); \n  private final XMPPFailureReporter failureReporter = context.mock(XMPPFailureReporter.class);\n  private final AuctionEventListener listener = context.mock(AuctionEventListener.class);\n  private final AuctionMessageTranslator translator = new AuctionMessageTranslator(SNIPER_ID, listener, failureReporter);\n  \n  @Test public void \n  notifiesAuctionClosedWhenCloseMessageReceived() { \n    context.checking(new Expectations() {{ \n      exactly(1).of(listener).auctionClosed(); \n    }}); \n  \n    Message message = new Message(); \n    message.setBody(\"SOLVersion: 1.1; Event: CLOSE;\"); \n    \n    translator.processMessage(UNUSED_CHAT, message); \n  } \n  \n  @Test public void \n  notifiesBidDetailsWhenCurrentPriceMessageReceivedFromOtherBidder() { \n    context.checking(new Expectations() {{ \n      exactly(1).of(listener).currentPrice(192, 7, PriceSource.FromOtherBidder); \n    }}); \n    \n    Message message = new Message(); \n    message.setBody(\"SOLVersion: 1.1; Event: PRICE; CurrentPrice: 192; Increment: 7; Bidder: Someone else;\");\n    \n    translator.processMessage(UNUSED_CHAT, message); \n  } \n\n  @Test public void \n  notifiesBidDetailsWhenCurrentPriceMessageReceivedFromSniper() { \n    context.checking(new Expectations() {{ \n      exactly(1).of(listener).currentPrice(192, 7, PriceSource.FromSniper); \n    }}); \n    \n    Message message = new Message(); \n    message.setBody(\"SOLVersion: 1.1; Event: PRICE; CurrentPrice: 192; Increment: 7; Bidder: \"\n                    + SNIPER_ID + \";\");\n    \n    translator.processMessage(UNUSED_CHAT, message); \n  } \n\n  @Test public void \n  notifiesAuctionFailedWhenBadMessageReceived() { \n    String badMessage = \"a bad message\";\n    expectFailureWithMessage(badMessage);\n    \n    translator.processMessage(UNUSED_CHAT, message(badMessage)); \n  } \n\n  @Test public void \n  notifiesAuctionFailedWhenEventTypeMissing() { \n    String badMessage = \"SOLVersion: 1.1; CurrentPrice: 234; Increment: 5; Bidder: \" + SNIPER_ID + \";\";\n    expectFailureWithMessage(badMessage);\n\n    translator.processMessage(UNUSED_CHAT, message(badMessage)); \n  } \n\n  private Message message(String body) { \n    Message message = new Message(); \n    message.setBody(body); \n    return message; \n  } \n  \n  private void expectFailureWithMessage(final String badMessage) { \n    context.checking(new Expectations() {{  \n      oneOf(listener).auctionFailed(); \n      oneOf(failureReporter).cannotTranslateMessage( \n                               with(SNIPER_ID), with(badMessage), \n                               with(any(Exception.class))); \n    }}); \n  } \n\n} \n"
  },
  {
    "path": "test/unit/test/auctionsniper/xmpp/LoggingXMPPFailureReporterTest.java",
    "content": "package test.auctionsniper.xmpp;\n\nimport java.util.logging.LogManager;\nimport java.util.logging.Logger;\n\nimport org.jmock.Expectations;\nimport org.jmock.Mockery;\nimport org.jmock.integration.junit4.JMock;\nimport org.jmock.lib.legacy.ClassImposteriser;\nimport org.junit.AfterClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport auctionsniper.xmpp.LoggingXMPPFailureReporter;\n\n@RunWith(JMock.class) \npublic class LoggingXMPPFailureReporterTest { \n  private final Mockery context = new Mockery() {{ \n    setImposteriser(ClassImposteriser.INSTANCE); \n  }}; \n  final Logger logger = context.mock(Logger.class); \n  final LoggingXMPPFailureReporter reporter = new LoggingXMPPFailureReporter(logger);\n  \n  @AfterClass public static void resetLogging() { \n    LogManager.getLogManager().reset(); \n  } \n  @Test public void \n  writesMessageTranslationFailureToLog() { \n    context.checking(new Expectations() {{ \n      oneOf(logger).severe(\"<auction id> \" \n                         + \"Could not translate message \\\"bad message\\\" \" \n                         + \"because \\\"java.lang.Exception: an exception\\\"\"); \n    }}); \n    \n    reporter.cannotTranslateMessage(\"auction id\", \"bad message\", \n                                    new Exception(\"an exception\")); \n  } \n} \n"
  },
  {
    "path": "tools/openfire-version-is-3.6.txt",
    "content": ""
  }
]