diff options
| author | Andrew Gallant (Ocelot) <[email protected]> | 2012-05-10 17:01:42 -0400 |
|---|---|---|
| committer | Andrew Gallant (Ocelot) <[email protected]> | 2012-05-10 17:01:42 -0400 |
| commit | b618b2ea09167306cfe29b6966faf184bc893c2d (patch) | |
| tree | ebd8b505ebd83db1b891bc7a7f70d75f26e581e6 /xgb_test.go | |
| parent | b10760ea62c5c071496a71d1d9ab6752989a309f (diff) | |
a huge commit. splitting extensions into their own sub-packages.
Diffstat (limited to 'xgb_test.go')
| -rw-r--r-- | xgb_test.go | 376 |
1 files changed, 0 insertions, 376 deletions
diff --git a/xgb_test.go b/xgb_test.go deleted file mode 100644 index d0e840a..0000000 --- a/xgb_test.go +++ /dev/null @@ -1,376 +0,0 @@ -package xgb - -/* - Tests for XGB. - - These tests only test the core X protocol at the moment. It isn't even - close to complete coverage (and probably never will be), but it does test - a number of different corners: requests with no replies, requests without - replies, checked (i.e., synchronous) errors, unchecked (i.e., asynchronous) - errors, and sequence number wrapping. - - There are also a couple of benchmarks that show the difference between - correctly issuing lots of requests and gathering replies and - incorrectly doing the same. (This particular difference is one of the - claimed advantages of the XCB, and therefore XGB, family. -*/ - -import ( - "fmt" - "log" - "math/rand" - "testing" - "time" -) - -// The X connection used throughout testing. -var X *Conn - -// init initializes the X connection, seeds the RNG and starts waiting -// for events. -func init() { - var err error - - X, err = NewConn() - if err != nil { - log.Fatal(err) - } - - rand.Seed(time.Now().UnixNano()) - - go grabEvents() -} - -/******************************************************************************/ -// Tests -/******************************************************************************/ - -// TestSynchronousError purposefully causes a BadWindow error in a -// MapWindow request, and checks it synchronously. -func TestSynchronousError(t *testing.T) { - err := X.MapWindowChecked(0).Check() // resource id 0 is always invalid - if err == nil { - t.Fatalf("MapWindow: A MapWindow request that should return an " + - "error has returned a nil error.") - } - verifyMapWindowError(t, err) -} - -// TestAsynchronousError does the same thing as TestSynchronousError, but -// grabs the error asynchronously instead. -func TestAsynchronousError(t *testing.T) { - X.MapWindow(0) // resource id 0 is always invalid - - evOrErr := waitForEvent(t, 5) - if evOrErr.ev != nil { - t.Fatalf("After issuing an erroneous MapWindow request, we have "+ - "received an event rather than an error: %s", evOrErr.ev) - } - verifyMapWindowError(t, evOrErr.err) -} - -// TestCookieBuffer issues (2^16) + n requets *without* replies to guarantee -// that the sequence number wraps and that the cookie buffer will have to -// flush itself (since there are no replies coming in to flush it). -// And just like TestSequenceWrap, we issue another request with a reply -// at the end to make sure XGB is still working properly. -func TestCookieBuffer(t *testing.T) { - n := (1 << 16) + 10 - for i := 0; i < n; i++ { - X.NoOperation() - } - TestProperty(t) -} - -// TestSequenceWrap issues (2^16) + n requests w/ replies to guarantee that the -// sequence number (which is a 16 bit integer) will wrap. It then issues one -// final request to ensure things still work properly. -func TestSequenceWrap(t *testing.T) { - n := (1 << 16) + 10 - for i := 0; i < n; i++ { - _, err := X.InternAtom(false, 5, "RANDO").Reply() - if err != nil { - t.Fatalf("InternAtom: %s", err) - } - } - TestProperty(t) -} - -// TestProperty tests whether a random value can be set and read. -func TestProperty(t *testing.T) { - propName := randString(20) // whatevs - writeVal := randString(20) - readVal, err := changeAndGetProp(propName, writeVal) - if err != nil { - t.Error(err) - } - - if readVal != writeVal { - t.Errorf("The value written, '%s', is not the same as the "+ - "value read '%s'.", writeVal, readVal) - } -} - -// TestWindowEvents creates a window, maps it, listens for configure notify -// events, issues a configure request, and checks for the appropriate -// configure notify event. -// This probably violates the notion of "test one thing and test it well," -// but testing X stuff is unique since it involves so much state. -// Each request is checked to make sure there are no errors returned. If there -// is an error, the test is failed. -// You may see a window appear quickly and then disappear. Do not be alarmed :P -// It's possible that this test will yield a false negative because we cannot -// control our environment. That is, the window manager could override the -// placement set. However, we set override redirect on the window, so the -// window manager *shouldn't* touch our window if it is well-behaved. -func TestWindowEvents(t *testing.T) { - // The geometry to set the window. - gx, gy, gw, gh := 200, 400, 1000, 300 - - wid, err := X.NewWindowId() - if err != nil { - t.Fatalf("NewId: %s", err) - } - - screen := X.DefaultScreen() // alias - err = X.CreateWindowChecked(screen.RootDepth, wid, screen.Root, - 0, 0, 500, 500, 0, - WindowClassInputOutput, screen.RootVisual, - CwBackPixel|CwOverrideRedirect, []uint32{0xffffffff, 1}).Check() - if err != nil { - t.Fatalf("CreateWindow: %s", err) - } - - err = X.MapWindowChecked(wid).Check() - if err != nil { - t.Fatalf("MapWindow: %s", err) - } - - // We don't listen in the CreateWindow request so that we don't get - // a MapNotify event. - err = X.ChangeWindowAttributesChecked(wid, - CwEventMask, []uint32{EventMaskStructureNotify}).Check() - if err != nil { - t.Fatalf("ChangeWindowAttributes: %s", err) - } - - err = X.ConfigureWindowChecked(wid, - ConfigWindowX|ConfigWindowY| - ConfigWindowWidth|ConfigWindowHeight, - []uint32{uint32(gx), uint32(gy), uint32(gw), uint32(gh)}).Check() - if err != nil { - t.Fatalf("ConfigureWindow: %s", err) - } - - err = X.ConfigureWindowChecked(wid, - ConfigWindowX|ConfigWindowY| - ConfigWindowWidth|ConfigWindowHeight, - []uint32{uint32(gx + 2), uint32(gy), uint32(gw), uint32(gh)}).Check() - if err != nil { - t.Fatalf("ConfigureWindow: %s", err) - } - - err = X.ConfigureWindowChecked(wid, - ConfigWindowX|ConfigWindowY| - ConfigWindowWidth|ConfigWindowHeight, - []uint32{uint32(gx + 1), uint32(gy), uint32(gw), uint32(gh)}).Check() - if err != nil { - t.Fatalf("ConfigureWindow: %s", err) - } - - TestProperty(t) - - evOrErr := waitForEvent(t, 5) - switch event := evOrErr.ev.(type) { - case ConfigureNotifyEvent: - if event.X != int16(gx) { - t.Fatalf("x was set to %d but ConfigureNotify reports %d", - gx, event.X) - } - if event.Y != int16(gy) { - t.Fatalf("y was set to %d but ConfigureNotify reports %d", - gy, event.Y) - } - if event.Width != uint16(gw) { - t.Fatalf("width was set to %d but ConfigureNotify reports %d", - gw, event.Width) - } - if event.Height != uint16(gh) { - t.Fatalf("height was set to %d but ConfigureNotify reports %d", - gh, event.Height) - } - default: - t.Fatalf("Expected a ConfigureNotifyEvent but got %T instead.", event) - } - - // Okay, clean up! - err = X.ChangeWindowAttributesChecked(wid, - CwEventMask, []uint32{0}).Check() - if err != nil { - t.Fatalf("ChangeWindowAttributes: %s", err) - } - - err = X.DestroyWindowChecked(wid).Check() - if err != nil { - t.Fatalf("DestroyWindow: %s", err) - } -} - -/******************************************************************************/ -// Benchmarks -/******************************************************************************/ - -// BenchmarkInternAtomsGood shows how many requests with replies -// *should* be sent and gathered from the server. Namely, send as many -// requests as you can at once, then go back and gather up all the replies. -// More importantly, this approach can exploit parallelism when -// GOMAXPROCS > 1. -// Run with `go test -run 'nomatch' -bench '.*' -cpu 1,2,6` if you have -// multiple cores to see the improvement that parallelism brings. -func BenchmarkInternAtomsGood(b *testing.B) { - b.StopTimer() - names := seqNames(b.N) - - b.StartTimer() - cookies := make([]InternAtomCookie, b.N) - for i := 0; i < b.N; i++ { - cookies[i] = X.InternAtom(false, uint16(len(names[i])), names[i]) - } - for _, cookie := range cookies { - cookie.Reply() - } -} - -// BenchmarkInternAtomsBad shows how *not* to issue a lot of requests with -// replies. Namely, each subsequent request isn't issued *until* the last -// reply is made. This implies a round trip to the X server for every -// iteration. -func BenchmarkInternAtomsPoor(b *testing.B) { - b.StopTimer() - names := seqNames(b.N) - - b.StartTimer() - for i := 0; i < b.N; i++ { - X.InternAtom(false, uint16(len(names[i])), names[i]).Reply() - } -} - -/******************************************************************************/ -// Helper functions -/******************************************************************************/ - -// changeAndGetProp sets property 'prop' with value 'val'. -// It then gets the value of that property and returns it. -// (It's used to check that the 'val' going in is the same 'val' going out.) -// It tests both requests with and without replies (GetProperty and -// ChangeProperty respectively.) -func changeAndGetProp(prop, val string) (string, error) { - propAtom, err := X.InternAtom(false, uint16(len(prop)), prop).Reply() - if err != nil { - return "", fmt.Errorf("InternAtom: %s", err) - } - - typName := "UTF8_STRING" - typAtom, err := X.InternAtom(false, uint16(len(typName)), typName).Reply() - if err != nil { - return "", fmt.Errorf("InternAtom: %s", err) - } - - err = X.ChangePropertyChecked(PropModeReplace, X.DefaultScreen().Root, - propAtom.Atom, typAtom.Atom, 8, uint32(len(val)), []byte(val)).Check() - if err != nil { - return "", fmt.Errorf("ChangeProperty: %s", err) - } - - reply, err := X.GetProperty(false, X.DefaultScreen().Root, propAtom.Atom, - GetPropertyTypeAny, 0, (1<<32)-1).Reply() - if err != nil { - return "", fmt.Errorf("GetProperty: %s", err) - } - if reply.Format != 8 { - return "", fmt.Errorf("Property reply format is %d but it should be 8.", - reply.Format) - } - - return string(reply.Value), nil -} - -// verifyMapWindowError takes an error that is returned with an invalid -// MapWindow request with a window Id of 0 and makes sure the error is the -// right type and contains the correct values. -func verifyMapWindowError(t *testing.T, err error) { - switch e := err.(type) { - case WindowError: - if e.BadValue != 0 { - t.Fatalf("WindowError should report a bad value of 0 but "+ - "it reports %d instead.", e.BadValue) - } - if e.MajorOpcode != 8 { - t.Fatalf("WindowError should report a major opcode of 8 "+ - "(which is a MapWindow request), but it reports %d instead.", - e.MajorOpcode) - } - default: - t.Fatalf("Expected a WindowError but got %T instead.", e) - } -} - -// randString generates a random string of length n. -func randString(n int) string { - byts := make([]byte, n) - for i := 0; i < n; i++ { - rando := rand.Intn(53) - switch { - case rando <= 25: - byts[i] = byte(65 + rando) - case rando <= 51: - byts[i] = byte(97 + rando - 26) - default: - byts[i] = ' ' - } - } - return string(byts) -} - -// seqNames creates a slice of NAME0, NAME1, ..., NAMEN. -func seqNames(n int) []string { - names := make([]string, n) - for i := range names { - names[i] = fmt.Sprintf("NAME%d", i) - } - return names -} - -// evErr represents a value that is either an event or an error. -type evErr struct { - ev Event - err Error -} - -// channel used to pass evErrs. -var evOrErrChan = make(chan evErr, 0) - -// grabEvents is a goroutine that reads events off the wire. -// We used this instead of WaitForEvent directly in our tests so that -// we can timeout and fail a test. -func grabEvents() { - for { - ev, err := X.WaitForEvent() - evOrErrChan <- evErr{ev, err} - } -} - -// waitForEvent asks the evOrErrChan channel for an event. -// If it doesn't get an event in 'n' seconds, the current test is failed. -func waitForEvent(t *testing.T, n int) evErr { - var evOrErr evErr - - select { - case evOrErr = <-evOrErrChan: - case <-time.After(time.Second * 5): - t.Fatalf("After waiting 5 seconds for an event or an error, " + - "we have timed out.") - } - - return evOrErr -} |
