// Copyright (c) Acrosync LLC. All rights reserved. // Free for personal use and commercial trial // Commercial use requires per-user licenses available from https://duplicacy.com package duplicacy import ( "bytes" "io" "io/ioutil" "time" crypto_rand "crypto/rand" "testing" ) func TestMatchPattern(t *testing.T) { // Test cases were copied from Matching Wildcards: An Empirical Way to Tame an Algorithm // By Kirk J. Krauss, October 07, 2014 DATA := []struct { text string pattern string matched bool }{ // Cases with repeating character sequences. {"abcccd", "*ccd", true}, {"mississipissippi", "*issip*ss*", true}, {"xxxx*zzzzzzzzy*f", "xxxx*zzy*fffff", false}, {"xxxx*zzzzzzzzy*f", "xxx*zzy*f", true}, {"xxxxzzzzzzzzyf", "xxxx*zzy*fffff", false}, {"xxxxzzzzzzzzyf", "xxxx*zzy*f", true}, {"xyxyxyzyxyz", "xy*z*xyz", true}, {"mississippi", "*sip*", true}, {"xyxyxyxyz", "xy*xyz", true}, {"mississippi", "mi*sip*", true}, {"ababac", "*abac*", true}, {"ababac", "*abac*", true}, {"aaazz", "a*zz*", true}, {"a12b12", "*12*23", false}, {"a12b12", "a12b", false}, {"a12b12", "*12*12*", true}, // More double wildcard scenarios. {"XYXYXYZYXYz", "XY*Z*XYz", true}, {"missisSIPpi", "*SIP*", true}, {"mississipPI", "*issip*PI", true}, {"xyxyxyxyz", "xy*xyz", true}, {"miSsissippi", "mi*sip*", true}, {"miSsissippi", "mi*Sip*", false}, {"abAbac", "*Abac*", true}, {"abAbac", "*Abac*", true}, {"aAazz", "a*zz*", true}, {"A12b12", "*12*23", false}, {"a12B12", "*12*12*", true}, {"oWn", "*oWn*", true}, // Completely tame (no wildcards) cases. {"bLah", "bLah", true}, {"bLah", "bLaH", false}, // Simple mixed wildcard tests suggested by IBMer Marlin Deckert. {"a", "*?", true}, {"ab", "*?", true}, {"abc", "*?", true}, // More mixed wildcard tests including coverage for false positives. {"a", "??", false}, {"ab", "?*?", true}, {"ab", "*?*?*", true}, {"abc", "?*?*?", true}, {"abc", "?*?*&?", false}, {"abcd", "?b*??", true}, {"abcd", "?a*??", false}, {"abcd", "?*?c?", true}, {"abcd", "?*?d?", false}, {"abcde", "?*b*?*d*?", true}, // Single-character-match cases. {"bLah", "bL?h", true}, {"bLaaa", "bLa?", false}, {"bLah", "bLa?", true}, {"bLaH", "?Lah", false}, {"bLaH", "?LaH", true}, } for _, data := range DATA { if matchPattern(data.text, data.pattern) != data.matched { t.Errorf("text: %s, pattern %s, expected: %t", data.text, data.pattern, data.matched) } } for _, pattern := range []string{ "+", "-", "i:", "e:", "+a", "-a", "i:a", "e:a"} { if IsUnspecifiedFilter(pattern) { t.Errorf("pattern %s has a specified filter", pattern) } } for _, pattern := range []string{ "i", "e", "ia", "ib", "a", "b"} { if !IsUnspecifiedFilter(pattern) { t.Errorf("pattern %s does not have a specified filter", pattern) } } } func TestRateLimit(t *testing.T) { content := make([]byte, 100*1024) _, err := crypto_rand.Read(content) if err != nil { t.Errorf("Error generating random content: %v", err) return } expectedRate := 10 rateLimiter := CreateRateLimitedReader(content, expectedRate) startTime := time.Now() n, err := io.Copy(ioutil.Discard, rateLimiter) if err != nil { t.Errorf("Error reading from the rate limited reader: %v", err) return } if int(n) != len(content) { t.Errorf("Wrote %d bytes instead of %d", n, len(content)) return } elapsed := time.Since(startTime) actualRate := float64(len(content)) / elapsed.Seconds() / 1024 t.Logf("Elapsed time: %s, actual rate: %.3f kB/s, expected rate: %d kB/s", elapsed, actualRate, expectedRate) startTime = time.Now() n, err = RateLimitedCopy(ioutil.Discard, bytes.NewBuffer(content), expectedRate) if err != nil { t.Errorf("Error writing with rate limit: %v", err) return } if int(n) != len(content) { t.Errorf("Copied %d bytes instead of %d", n, len(content)) return } elapsed = time.Since(startTime) actualRate = float64(len(content)) / elapsed.Seconds() / 1024 t.Logf("Elapsed time: %s, actual rate: %.3f kB/s, expected rate: %d kB/s", elapsed, actualRate, expectedRate) }