Index: tests/collections/string-api-coverage.cfa
===================================================================
--- tests/collections/string-api-coverage.cfa	(revision 7b0e8b700f1cc88f52caa78276608cd8378524a0)
+++ tests/collections/string-api-coverage.cfa	(revision 6f7aff39a23cd54f3b8131e9f26394eb753dce9c)
@@ -1,3 +1,4 @@
 #include <containers/string.hfa>
+#include <string_sharectx.hfa>
 
 void assertWellFormedHandleList( int maxLen ) { // with(HeapArea)
@@ -25,4 +26,10 @@
 
 int main () {
+
+    #ifdef STRING_SHARING_OFF
+    sout | "string sharing disabled";
+    string_sharectx c = { NO_SHARING };
+    #endif
+
     string s = "hello";
     string s2 = "hello";
Index: tests/collections/string-ctx-manage.cfa
===================================================================
--- tests/collections/string-ctx-manage.cfa	(revision 7b0e8b700f1cc88f52caa78276608cd8378524a0)
+++ tests/collections/string-ctx-manage.cfa	(revision 6f7aff39a23cd54f3b8131e9f26394eb753dce9c)
@@ -3,13 +3,32 @@
 #include <string_res.hfa>
 
+// In these tests, shared heaps are never remotely full and string sizes are tiny.
+// So here, the SUT should put a yes-sharing string in a heap with lots of spare room.
+// The SUT should always keep a no-sharing string's buffer 1x--2x the string's size.
+// This check uses 3x as a heuristic split between those cases.
+void assertSpareRoomInHeap( string & s, bool expectOversized ) {
+    double bytesInHeap = DEBUG_string_bytes_in_heap(s.inner->Handle.ulink);
+    double bytesUsed =  s.inner->Handle.lnth;
+    double overhead = bytesInHeap / bytesUsed;
+    assert (overhead >= 1);
+    if ( expectOversized )
+        assert( overhead >= 3.0 );
+    else 
+        assert( overhead < 3.0 );
+}
+
 void baseline() {
     string x = "hi";
+    assertSpareRoomInHeap( x, true );
 
     string y = x; // construct y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
     assert( y.inner->Handle.s == x.inner->Handle.s);
     sout | y; // hi
 
     x = "bye";
+    assertSpareRoomInHeap( x, true );
     y = x; // y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
     assert( y.inner->Handle.s == x.inner->Handle.s);
     sout | y; // bye
@@ -18,12 +37,16 @@
 void eagerCopy() {
     string x = "hi";
+    assertSpareRoomInHeap( x, true );
     string_sharectx c = { NEW_SHARING };
 
     string y = x; // construct y in different context => eager copy
+    assertSpareRoomInHeap( y, true );
     assert( y.inner->Handle.s != x.inner->Handle.s);
     sout | y; // hi
 
     x = "bye";
+    assertSpareRoomInHeap( x, true );
     y = x; // y was already in different context => eager copy
+    assertSpareRoomInHeap( y, true );
     assert( y.inner->Handle.s != x.inner->Handle.s);
     sout | y; // bye
@@ -32,15 +55,17 @@
 void soloAlloc() {
     string x = "hi";
+    assertSpareRoomInHeap( x, true );
     string_sharectx c = { NO_SHARING };
     
     string y = x; // y allocates into private pad, implying eager copy
+    assertSpareRoomInHeap( y, false );
     assert( y.inner->Handle.s != x.inner->Handle.s);
-    assert( DEBUG_string_bytes_in_heap(y.inner->Handle.ulink) == y.inner->Handle.lnth );  // y is in a perfectly fitting heap
     sout | y; // hi
 
     x = "bye";
+    assertSpareRoomInHeap( x, true );
     y = x; // into private y => eager copy
+    assertSpareRoomInHeap( y, false );
     assert( y.inner->Handle.s != x.inner->Handle.s);
-//    assert( DEBUG_string_bytes_in_heap(y.inner->Handle.ulink) == y.inner->Handle.lnth );  // optimization required
     sout | y; // bye
 }
