         else
             # insert about 25 characters at random
             s = s.slice(0,i) + Math.random().toString(36).slice(2) + s.slice(i)
-        @set(s)
+        @_doc.from_str(s)
 
     test_random_edits: (opts) =>
         opts = defaults opts,

            @_patch_list.add(@_get_patches())
            value = @_patch_list.value()
            @_last = value
            @_doc.set(value)
            @_patches_table.on('change', @_handle_patch_update)
            @_patches_table.on('before-change', => @emit('before-change'))
            cb()

            doc               : new StringDocument(opts.default)

    set: (value) ->
        @_doc.from_str(value)

    get: ->
        @_doc.to_str()

# A document that represents an arbitrary JSON-able Javascript object.
class ObjectDocument
    constructor: (@_value={}) ->
    from_str: (value) ->
        try
            @_value = misc.from_json(value)
        catch err
            console.warn("error parsing JSON", err)
            # leaves @_value unchanged, so JSON stays valid
    to_str: ->
        misc.to_json(@_value)
    # Underlying Javascript object -- safe to directly edit
    to_obj: ->
        return @_value

class exports.SyncObject extends SyncDoc
