func TestPatchingStart(t *testing.T) { LOCAL := bytes.NewReader([]byte("48 brown fox jumped over the lazy dog")) out := bytes.NewBuffer(nil) missing := []patcher.MissingBlockSpan{ { BlockSize: BLOCKSIZE, StartBlock: 0, EndBlock: 2, Hasher: md5.New(), ExpectedSums: REFERENCE_HASHES[0:3], }, } matched := []patcher.FoundBlockSpan{ { BlockSize: BLOCKSIZE, StartBlock: 3, EndBlock: 11, MatchOffset: 5, }, } err := SequentialPatcher( LOCAL, blocksources.NewReadSeekerBlockSource( stringToReadSeeker(REFERENCE_STRING), blocksources.MakeNullFixedSizeResolver(BLOCKSIZE), ), missing, matched, 1024, out, ) if err != nil { t.Fatal(err) } if result, err := ioutil.ReadAll(out); err == nil { t.Logf("String split is: \"%v\"", strings.Join(REFERENCE_BLOCKS, "\", \"")) if bytes.Compare(result, []byte(REFERENCE_STRING)) != 0 { t.Errorf("Result does not equal reference: \"%s\" vs \"%v\"", result, REFERENCE_STRING) } } else { t.Fatal(err) } // }
func TestPatchingEntirelyMissing(t *testing.T) { LOCAL := bytes.NewReader([]byte("")) out := bytes.NewBuffer(nil) missing := []patcher.MissingBlockSpan{ { BlockSize: BLOCKSIZE, StartBlock: 0, EndBlock: 10, Hasher: md5.New(), ExpectedSums: REFERENCE_HASHES[0:10], }, } matched := []patcher.FoundBlockSpan{} err := SequentialPatcher( LOCAL, blocksources.NewReadSeekerBlockSource( stringToReadSeeker(REFERENCE_STRING), blocksources.MakeNullFixedSizeResolver(BLOCKSIZE), ), missing, matched, 1024, out, ) if err != nil { t.Fatal(err) } if result, err := ioutil.ReadAll(out); err == nil { if bytes.Compare(result, []byte(REFERENCE_STRING)) != 0 { t.Errorf("Result does not equal reference: \"%s\" vs \"%v\"", result, REFERENCE_STRING) } } else { t.Fatal(err) } }
func Example() { // due to short example strings, use a very small block size // using one this small in practice would increase your file transfer! const blockSize = 4 // This is the "file" as described by the authoritive version const reference = "The quick brown fox jumped over the lazy dog" // This is what we have locally. Not too far off, but not correct. const localVersion = "The qwik brown fox jumped 0v3r the lazy" generator := filechecksum.NewFileChecksumGenerator(blockSize) _, referenceFileIndex, _, err := indexbuilder.BuildIndexFromString( generator, reference, ) if err != nil { return } referenceAsBytes := []byte(reference) localVersionAsBytes := []byte(localVersion) blockCount := len(referenceAsBytes) / blockSize if len(referenceAsBytes)%blockSize != 0 { blockCount++ } inputFile := bytes.NewReader(localVersionAsBytes) patchedFile := bytes.NewBuffer(nil) // This is more complicated than usual, because we're using in-memory // "files" and sources. Normally you would use MakeRSync summary := &BasicSummary{ ChecksumIndex: referenceFileIndex, ChecksumLookup: nil, BlockCount: uint(blockCount), BlockSize: blockSize, FileSize: int64(len(referenceAsBytes)), } rsync := &RSync{ Input: inputFile, Output: patchedFile, Source: blocksources.NewReadSeekerBlockSource( bytes.NewReader(referenceAsBytes), blocksources.MakeNullFixedSizeResolver(uint64(blockSize)), ), Summary: summary, OnClose: nil, } if err := rsync.Patch(); err != nil { fmt.Printf("Error: %v", err) return } fmt.Printf("Patched result: \"%s\"\n", patchedFile.Bytes()) // Output: // Patched result: "The quick brown fox jumped over the lazy dog" }