From e478250f499385a0299d5182dd40f640aaa1270a Mon Sep 17 00:00:00 2001
From: Volker Schukai <volker.schukai@schukai.com>
Date: Mon, 17 Oct 2022 15:54:44 +0200
Subject: [PATCH] feat add  HasOnChangeHook and RemoveOnChangeHook

---
 README.md            | 19 +++++++++--
 change.go            | 28 ++++++++++++++--
 change_test.go       | 77 +++++++++++++++++++++++++++++++++++++-------
 http-handler_test.go | 14 +++++---
 watch_test.go        | 15 ++++++---
 5 files changed, 128 insertions(+), 25 deletions(-)

diff --git a/README.md b/README.md
index f794823..4333b47 100644
--- a/README.md
+++ b/README.md
@@ -303,6 +303,14 @@ import (
    "gitlab.schukai.com/oss/libraries/go/application/configuration"
 )
 
+type ChangeEventHandler struct {
+  callback func(event configuration.ChangeEvent)
+}
+
+func (c *ChangeEventHandler) Handle(event configuration.ChangeEvent) {
+  c.callback(event)
+}
+
 func main() {
    config := struct {
       Host string
@@ -314,12 +322,17 @@ func main() {
 
    closeChan := make(chan bool)
 
-   s.OnChange(func(event configuration.ChangeEvent) {
+   var h configuration.EventHook
+   h = &ChangeEventHandler{
+     callback: func(event configuration.ChangeEvent) {
       log := event.Changlog
-      msg := fmt.Sprintf("Change from %s to %s", log[0].From, log[0].To)
+      msg = fmt.Sprintf("Change from %s to %s", log[0].From, log[0].To)
       fmt.Println(msg)
       closeChan <- true
-   })
+    },
+  }
+
+   s.OnChange(h)   
 
    c := s.Config()
    c.Host = "www.example.com"
diff --git a/change.go b/change.go
index 18c63d9..f513670 100644
--- a/change.go
+++ b/change.go
@@ -11,16 +11,40 @@ type ChangeEvent struct {
 	Changlog diff.Changelog
 }
 
-type EventHook func(event ChangeEvent)
+type EventHook interface {
+	Handle(event ChangeEvent)
+}
 
+// OnChange registers a hook that is called when the configuration changes.
 func (s *Settings[C]) OnChange(hook EventHook) *Settings[C] {
 	s.hooks.change = append(s.hooks.change, hook)
 	return s
 }
 
+// HasOnChangeHook returns true if there are registered hooks.
+func (s *Settings[C]) HasOnChangeHook(hook EventHook) *Settings[C] {
+	for _, h := range s.hooks.change {
+		if h == hook {
+			break
+		}
+	}
+	return s
+}
+
+// RemoveOnChangeHook removes a change hook from the list of hooks.
+func (s *Settings[C]) RemoveOnChangeHook(hook EventHook) *Settings[C] {
+	for i, h := range s.hooks.change {
+		if h == hook {
+			s.hooks.change = append(s.hooks.change[:i], s.hooks.change[i+1:]...)
+			break
+		}
+	}
+	return s
+}
+
 func (s *Settings[C]) notifyChangeHooks(changelog diff.Changelog) *Settings[C] {
 	for _, h := range s.hooks.change {
-		h(ChangeEvent{Changlog: changelog})
+		h.Handle(ChangeEvent{Changlog: changelog})
 	}
 	return s
 }
diff --git a/change_test.go b/change_test.go
index 2b8d8ad..7414a81 100644
--- a/change_test.go
+++ b/change_test.go
@@ -11,6 +11,49 @@ import (
 	"time"
 )
 
+type mockTestEventHandler struct {
+	EventHook
+}
+
+func (m *mockTestEventHandler) Handle(event ChangeEvent) {
+	// do nothing
+
+}
+
+func TestAddRemoveHook(t *testing.T) {
+
+	config := struct {
+		Host string
+	}{
+		Host: "localhost",
+	}
+
+	s := New(config)
+
+	var h EventHook
+	h = &mockTestEventHandler{}
+	s.OnChange(h)
+
+	if len(s.hooks.change) != 1 {
+		t.Error("Expected 1 got ", len(s.hooks.change))
+	}
+
+	s.RemoveOnChangeHook(h)
+
+	if len(s.hooks.change) != 0 {
+		t.Error("Expected 0 got ", len(s.hooks.change))
+	}
+
+}
+
+type ChangeEventTester struct {
+	callback func(event ChangeEvent)
+}
+
+func (c *ChangeEventTester) Handle(event ChangeEvent) {
+	c.callback(event)
+}
+
 func TestReadmeExample(t *testing.T) {
 
 	config := struct {
@@ -24,13 +67,19 @@ func TestReadmeExample(t *testing.T) {
 	closeChan := make(chan bool)
 
 	msg := ""
-	s.OnChange(func(event ChangeEvent) {
-		log := event.Changlog
-		msg = fmt.Sprintf("Change from %s to %s", log[0].From, log[0].To)
-		// for Readme
-		//fmt.Println(msg)
-		closeChan <- true
-	})
+
+	var h EventHook
+	h = &ChangeEventTester{
+		callback: func(event ChangeEvent) {
+			log := event.Changlog
+			msg = fmt.Sprintf("Change from %s to %s", log[0].From, log[0].To)
+			// for Readme
+			//fmt.Println(msg)
+			closeChan <- true
+		},
+	}
+
+	s.OnChange(h)
 
 	c := s.Config()
 	c.Host = "www.example.com"
@@ -84,10 +133,16 @@ func TestCangeOnChange(t *testing.T) {
 	closeChan := make(chan bool)
 
 	counter := 0
-	s.OnChange(func(event ChangeEvent) {
-		counter++
-		closeChan <- true
-	})
+
+	var h EventHook
+	h = &ChangeEventTester{
+		callback: func(event ChangeEvent) {
+			counter++
+			closeChan <- true
+		},
+	}
+
+	s.OnChange(h)
 
 	c.A = "b"
 	s.SetConfig(c)
diff --git a/http-handler_test.go b/http-handler_test.go
index 1955070..7f1cdb5 100644
--- a/http-handler_test.go
+++ b/http-handler_test.go
@@ -271,10 +271,16 @@ func TestConfigurationServePostJson(t *testing.T) {
 
 	closeChan := make(chan bool)
 	counter := 0
-	s.OnChange(func(event ChangeEvent) {
-		counter++
-		closeChan <- true
-	})
+
+	var h EventHook
+	h = &ChangeEventTester{
+		callback: func(event ChangeEvent) {
+			counter++
+			closeChan <- true
+		},
+	}
+
+	s.OnChange(h)
 
 	// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
 	rr := httptest.NewRecorder()
diff --git a/watch_test.go b/watch_test.go
index b310b9e..aafb522 100644
--- a/watch_test.go
+++ b/watch_test.go
@@ -35,11 +35,16 @@ func TestWatch(t *testing.T) {
 
 	signal := make(chan bool)
 
-	c.OnChange(func(event ChangeEvent) {
-		assert.Equal(t, event.Changlog[0].From, "localhost")
-		assert.Equal(t, event.Changlog[0].To, "example.org")
-		signal <- true
-	})
+	var h EventHook
+	h = &ChangeEventTester{
+		callback: func(event ChangeEvent) {
+			assert.Equal(t, event.Changlog[0].From, "localhost")
+			assert.Equal(t, event.Changlog[0].To, "example.org")
+			signal <- true
+		},
+	}
+
+	c.OnChange(h)
 
 	c.Watch()
 
-- 
GitLab