diff --git a/.travis.yml b/.travis.yml
index 2603ca2c..661959fd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,3 +27,9 @@ script:
    - cd SampleProjects/TestSomething
    - bundle install
    - bundle exec arduino_ci.rb
+   - cd ../NetworkLib
+   - bundle install
+   - cd scripts
+   - bash -x ./install.sh
+   - cd ..
+   - bundle exec arduino_ci.rb
diff --git a/CHANGELOG.md b/CHANGELOG.md
index db353f1c..41b1714d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 ### Added
 - Add `__AVR__` to defines when compiling
 - Add support for `diditalPinToPort()`, `digitalPinToBitMask()`, and `portOutputRegister()`
+- Add stubs for `Client.h`, `IPAddress.h`, `Printable.h`, `Server.h`, and `Udp.h` 
 
 ### Changed
 - Move repository from https://github.com/ianfixes/arduino_ci to https://github.com/Arduino-CI/arduino_ci
diff --git a/SampleProjects/NetworkLib/.arduino-ci.yml b/SampleProjects/NetworkLib/.arduino-ci.yml
new file mode 100644
index 00000000..a242a79b
--- /dev/null
+++ b/SampleProjects/NetworkLib/.arduino-ci.yml
@@ -0,0 +1,11 @@
+unittest:
+  platforms:
+    - mega2560
+  libraries:
+    - "Ethernet"
+
+compile:
+  platforms:
+    - mega2560
+  libraries:
+    - "Ethernet"
diff --git a/SampleProjects/NetworkLib/.gitignore b/SampleProjects/NetworkLib/.gitignore
new file mode 100644
index 00000000..06de90aa
--- /dev/null
+++ b/SampleProjects/NetworkLib/.gitignore
@@ -0,0 +1 @@
+.bundle
\ No newline at end of file
diff --git a/SampleProjects/NetworkLib/Gemfile b/SampleProjects/NetworkLib/Gemfile
new file mode 100644
index 00000000..b2b3b1fd
--- /dev/null
+++ b/SampleProjects/NetworkLib/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'arduino_ci', path: '../../'
diff --git a/SampleProjects/NetworkLib/README.md b/SampleProjects/NetworkLib/README.md
new file mode 100644
index 00000000..b25d2e14
--- /dev/null
+++ b/SampleProjects/NetworkLib/README.md
@@ -0,0 +1,3 @@
+# NetworkLib
+
+This is an example of a library that depends on Ethernet.
diff --git a/SampleProjects/NetworkLib/examples/EthernetExample/EthernetExample.ino b/SampleProjects/NetworkLib/examples/EthernetExample/EthernetExample.ino
new file mode 100644
index 00000000..127afc76
--- /dev/null
+++ b/SampleProjects/NetworkLib/examples/EthernetExample/EthernetExample.ino
@@ -0,0 +1,6 @@
+#include <NetworkLib.h>
+// if it seems bare, that's because it's only meant to
+// demonstrate compilation -- that references work
+void setup() {}
+
+void loop() {}
diff --git a/SampleProjects/NetworkLib/library.properties b/SampleProjects/NetworkLib/library.properties
new file mode 100644
index 00000000..2efc89bd
--- /dev/null
+++ b/SampleProjects/NetworkLib/library.properties
@@ -0,0 +1,10 @@
+name=Ethernet
+version=0.1.0
+author=James Foster <arduino@jgfoster.net>
+maintainer=James Foster <arduino@jgfoster.net>
+sentence=Sample Ethernet library to validate Client/Server mocks
+paragraph=Sample Ethernet library to validate Client/Server mocks
+category=Other
+url=https://github.com/Arduino-CI/arduino_ci/SampleProjects/Ethernet
+architectures=avr,esp8266
+includes=NetworkLib.h
diff --git a/SampleProjects/NetworkLib/scripts/install.sh b/SampleProjects/NetworkLib/scripts/install.sh
new file mode 100755
index 00000000..c4eb0517
--- /dev/null
+++ b/SampleProjects/NetworkLib/scripts/install.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# if we don't have an Ethernet library already (say, in new install or for an automated test), 
+# then get the custom one we want to use for testing
+cd $(bundle exec arduino_library_location.rb)
+if [ ! -d ./Ethernet ] ; then
+  git clone https://github.com/arduino-libraries/Ethernet.git
+fi
diff --git a/SampleProjects/NetworkLib/src/NetworkLib.cpp b/SampleProjects/NetworkLib/src/NetworkLib.cpp
new file mode 100644
index 00000000..01e5d5b0
--- /dev/null
+++ b/SampleProjects/NetworkLib/src/NetworkLib.cpp
@@ -0,0 +1 @@
+#include "Ethernet.h"
diff --git a/SampleProjects/NetworkLib/src/NetworkLib.h b/SampleProjects/NetworkLib/src/NetworkLib.h
new file mode 100644
index 00000000..9ee81b24
--- /dev/null
+++ b/SampleProjects/NetworkLib/src/NetworkLib.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <Arduino.h>
diff --git a/SampleProjects/NetworkLib/test/test.cpp b/SampleProjects/NetworkLib/test/test.cpp
new file mode 100644
index 00000000..4c2d4eca
--- /dev/null
+++ b/SampleProjects/NetworkLib/test/test.cpp
@@ -0,0 +1,15 @@
+/*
+cd SampleProjects/NetworkLib
+bundle config --local path vendor/bundle
+bundle install
+bundle exec arduino_ci_remote.rb  --skip-compilation
+# bundle exec arduino_ci_remote.rb  --skip-examples-compilation
+*/
+
+#include <Arduino.h>
+#include <ArduinoUnitTests.h>
+#include <Ethernet.h>
+
+unittest(test) { assertEqual(EthernetNoHardware, Ethernet.hardwareStatus()); }
+
+unittest_main()
diff --git a/SampleProjects/TestSomething/test/clientServer.cpp b/SampleProjects/TestSomething/test/clientServer.cpp
new file mode 100644
index 00000000..f088c821
--- /dev/null
+++ b/SampleProjects/TestSomething/test/clientServer.cpp
@@ -0,0 +1,87 @@
+#include <Arduino.h>
+#include <ArduinoUnitTests.h>
+#include <Client.h>
+#include <IPAddress.h>
+#include <Printable.h>
+#include <Server.h>
+#include <Udp.h>
+
+// Provide some rudamentary tests for these classes
+// They get more thoroughly tested in SampleProjects/NetworkLib
+
+unittest(Client) {
+  Client client;
+  assertEqual(0, client.available());         // subclass of Stream
+  assertEqual(0, client.availableForWrite()); // subclass of Print
+  String outData = "Hello, world!";
+  client.println(outData);
+  String inData = client.readString();
+  assertEqual(outData + "\r\n", inData);
+}
+
+unittest(IPAddress) {
+  IPAddress ipAddress0;
+  assertEqual(0, ipAddress0.asWord());
+  uint32_t one = 0x01020304;
+  IPAddress ipAddress1(one);
+  assertEqual(one, ipAddress1.asWord());
+  IPAddress ipAddress2(2, 3, 4, 5);
+  assertEqual(0x05040302, ipAddress2.asWord());
+  uint8_t bytes[] = {3, 4, 5, 6};
+  IPAddress ipAddress3(bytes);
+  assertEqual(0x06050403, ipAddress3.asWord());
+  uint8_t *pBytes = ipAddress1.raw_address();
+  assertEqual(*(pBytes + 0), 4);
+  assertEqual(*(pBytes + 1), 3);
+  assertEqual(*(pBytes + 2), 2);
+  assertEqual(*(pBytes + 3), 1);
+  IPAddress ipAddress1a(one);
+  assertTrue(ipAddress1 == ipAddress1a);
+  assertTrue(ipAddress1 != ipAddress2);
+  assertEqual(1, ipAddress1[3]);
+  ipAddress1[1] = 11;
+  assertEqual(11, ipAddress1[1]);
+  assertEqual(1, ipAddress0 + 1);
+}
+
+class TestPrintable : public Printable {
+public:
+  virtual size_t printTo(Print &p) const {
+    p.print("TestPrintable");
+    return 13;
+  }
+};
+
+unittest(Printable) {
+  TestPrintable printable;
+  Client client;
+  client.print(printable);
+  assertEqual("TestPrintable", client.readString());
+}
+
+class TestServer : public Server {
+public:
+  uint8_t data;
+  virtual size_t write(uint8_t value) {
+    data = value;
+    return 1;
+  };
+};
+
+unittest(Server) {
+  TestServer server;
+  server.write(67);
+  assertEqual(67, server.data);
+}
+
+unittest(Udp) {
+  UDP udp;
+  assertEqual(0, udp.available());         // subclass of Stream
+  assertEqual(0, udp.availableForWrite()); // subclass of Print
+  String outData = "Hello, world!";
+  udp.println(outData);
+  String inData = udp.readString();
+  assertEqual(outData + "\r\n", inData);
+}
+
+unittest_main()
diff --git a/appveyor.yml b/appveyor.yml
index af4bd854..2a68c341 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -25,3 +25,9 @@ test_script:
   - cd SampleProjects\TestSomething
   - bundle install
   - bundle exec arduino_ci.rb
+  - cd ../NetworkLib
+  - bundle install
+  - cd scripts
+  - install.sh
+  - cd ..
+  - bundle exec arduino_ci.rb
diff --git a/cpp/arduino/Arduino.h b/cpp/arduino/Arduino.h
index e107126e..2c4f347e 100644
--- a/cpp/arduino/Arduino.h
+++ b/cpp/arduino/Arduino.h
@@ -9,6 +9,7 @@ Where possible, variable names from the Arduino library are used to avoid confli
 
 #include "ArduinoDefines.h"
 
+#include "IPAddress.h"
 #include "WCharacter.h"
 #include "WString.h"
 #include "Print.h"
diff --git a/cpp/arduino/Client.h b/cpp/arduino/Client.h
new file mode 100644
index 00000000..b08e183e
--- /dev/null
+++ b/cpp/arduino/Client.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <Stream.h>
+
+class Client : public Stream {
+public:
+  Client() {
+    // The Stream mock defines a String buffer but never puts anyting in it!
+    if (!mGodmodeDataIn) {
+      mGodmodeDataIn = new String;
+    }
+  }
+  ~Client() {
+    if (mGodmodeDataIn) {
+      delete mGodmodeDataIn;
+      mGodmodeDataIn = nullptr;
+    }
+  }
+  virtual size_t write(uint8_t value) {
+    mGodmodeDataIn->concat(value);
+    return 1;
+  }
+
+protected:
+  uint8_t *rawIPAddress(IPAddress &addr) { return addr.raw_address(); }
+};
diff --git a/cpp/arduino/IPAddress.h b/cpp/arduino/IPAddress.h
new file mode 100644
index 00000000..89a343e1
--- /dev/null
+++ b/cpp/arduino/IPAddress.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <stdint.h>
+
+class IPAddress {
+private:
+  union {
+    uint8_t bytes[4];
+    uint32_t dword;
+    operator uint8_t *() const { return (uint8_t *)bytes; }
+  } _address;
+
+public:
+  // Constructors
+  IPAddress() : IPAddress(0, 0, 0, 0) {}
+  IPAddress(uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4) {
+    _address.bytes[0] = octet1;
+    _address.bytes[1] = octet2;
+    _address.bytes[2] = octet3;
+    _address.bytes[3] = octet4;
+  }
+  IPAddress(uint32_t dword) { _address.dword = dword; }
+  IPAddress(const uint8_t bytes[]) {
+    _address.bytes[0] = bytes[0];
+    _address.bytes[1] = bytes[1];
+    _address.bytes[2] = bytes[2];
+    _address.bytes[3] = bytes[3];
+  }
+  IPAddress(unsigned long dword) { _address.dword = (uint32_t)dword; }
+
+  // Accessors
+  uint32_t asWord() const { return _address.dword; }
+  uint8_t *raw_address() { return _address.bytes; }
+
+  // Comparisons
+  bool operator==(const IPAddress &rhs) const {
+    return _address.dword == rhs.asWord();
+  }
+
+  bool operator!=(const IPAddress &rhs) const {
+    return _address.dword != rhs.asWord();
+  }
+
+  // Indexing
+  uint8_t operator[](int index) const { return _address.bytes[index]; }
+  uint8_t &operator[](int index) { return _address.bytes[index]; }
+
+  // Conversions
+  operator uint32_t() const { return _address.dword; };
+
+  friend class EthernetClass;
+  friend class UDP;
+  friend class Client;
+  friend class Server;
+  friend class DhcpClass;
+  friend class DNSClient;
+};
+
+const IPAddress INADDR_NONE(0, 0, 0, 0);
diff --git a/cpp/arduino/Print.h b/cpp/arduino/Print.h
index b7d8a522..261b116d 100644
--- a/cpp/arduino/Print.h
+++ b/cpp/arduino/Print.h
@@ -2,6 +2,8 @@
 
 #include <stdio.h>
 #include <avr/pgmspace.h>
+
+#include "Printable.h"
 #include "WString.h"
 
 #define DEC 10
@@ -12,22 +14,17 @@
 #endif
 #define BIN 2
 
-class Print;
-
-class Printable
-{
-  public:
-    virtual size_t printTo(Print& p) const = 0;
-};
-
 class Print
 {
+  private:
+    int write_error;
+  protected:
+    void setWriteError(int err = 1) { write_error = err; }
   public:
-    Print() {}
+    Print() : write_error(0) {}
 
-    // Arduino's version of this is richer but until I see an actual error case I'm not sure how to mock
-    int getWriteError() { return 0; }
-    void clearWriteError() { }
+    int getWriteError() { return write_error; }
+    void clearWriteError() { setWriteError(0); }
     virtual int availableForWrite() { return 0; }
 
     virtual size_t write(uint8_t) = 0;
diff --git a/cpp/arduino/Printable.h b/cpp/arduino/Printable.h
new file mode 100644
index 00000000..cdd361d3
--- /dev/null
+++ b/cpp/arduino/Printable.h
@@ -0,0 +1,8 @@
+#pragma once
+
+class Print;
+
+class Printable {
+public:
+  virtual size_t printTo(Print &p) const = 0;
+};
diff --git a/cpp/arduino/Server.h b/cpp/arduino/Server.h
new file mode 100644
index 00000000..dd1993ff
--- /dev/null
+++ b/cpp/arduino/Server.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <Stream.h>
+
+class Server : public Print {};
diff --git a/cpp/arduino/Udp.h b/cpp/arduino/Udp.h
new file mode 100644
index 00000000..8352f7f6
--- /dev/null
+++ b/cpp/arduino/Udp.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <IPAddress.h>
+#include <Stream.h>
+
+class UDP : public Stream {
+protected:
+  uint8_t *rawIPAddress(IPAddress &addr) { return addr.raw_address(); };
+
+public:
+  UDP() {
+    // The Stream mock defines a String buffer but never puts anyting in it!
+    if (!mGodmodeDataIn) {
+      mGodmodeDataIn = new String;
+    }
+  }
+  ~UDP() {
+    if (mGodmodeDataIn) {
+      delete mGodmodeDataIn;
+      mGodmodeDataIn = nullptr;
+    }
+  }
+  virtual size_t write(uint8_t value) {
+    mGodmodeDataIn->concat(value);
+    return 1;
+  }
+};