From 7f47aa08a83fe5686c116f9490b7f7135060dfe7 Mon Sep 17 00:00:00 2001 From: Yasuyuki Takeo Date: Sun, 11 Aug 2024 05:45:02 +0900 Subject: [PATCH] Add Text Dictionary service --- backend/pkg/textdic/parser_service.go | 29 ------- .../pkg/textdic/text_dictionary_service.go | 66 +++++++++++++++ ...est.go => text_dictionary_service_test.go} | 83 +++++++++++++++++-- 3 files changed, 143 insertions(+), 35 deletions(-) delete mode 100644 backend/pkg/textdic/parser_service.go create mode 100644 backend/pkg/textdic/text_dictionary_service.go rename backend/pkg/textdic/{parser_service_test.go => text_dictionary_service_test.go} (71%) diff --git a/backend/pkg/textdic/parser_service.go b/backend/pkg/textdic/parser_service.go deleted file mode 100644 index 65f1c49..0000000 --- a/backend/pkg/textdic/parser_service.go +++ /dev/null @@ -1,29 +0,0 @@ -package textdic - -import ( - "fmt" -) - -// parserService struct definition -type parserService struct{} - -// NewParserService creates and returns a new instance of parserService -func NewParserService() *parserService { - return &parserService{} -} - -// ProcessDictionary processes a given dictionary string and returns the parsed Nodes or an error -func (ps *parserService) ProcessDictionary(dic string) ([]Node, error) { - - // Use the new parser to parse the input - l := newLexer(dic) - - // Parse the input using the new parser - parsedNodes := ParseAndGetNodes(l) - - if len(parsedNodes) == 0 { - return nil, fmt.Errorf("no nodes were parsed") - } - - return parsedNodes, nil -} diff --git a/backend/pkg/textdic/text_dictionary_service.go b/backend/pkg/textdic/text_dictionary_service.go new file mode 100644 index 0000000..89743a8 --- /dev/null +++ b/backend/pkg/textdic/text_dictionary_service.go @@ -0,0 +1,66 @@ +package textdic + +import ( + "backend/pkg/logger" + "encoding/base64" + "fmt" + "golang.org/x/net/context" + "strings" + "unicode" +) + +// textDictionaryService struct definition +type textDictionaryService struct{} + +// NewTextDictionaryService creates and returns a new instance of textDictionaryService +func NewTextDictionaryService() *textDictionaryService { + return &textDictionaryService{} +} + +// Process processes a given dictionary string and returns the parsed Nodes or an error +func (tds *textDictionaryService) Process(ctx context.Context, dic string) ([]Node, error) { + + // Use the new parser to parse the input + l := newLexer(dic) + + // Parse the input using the new parser + parsedNodes := ParseAndGetNodes(l) + + if len(parsedNodes) == 0 { + err := fmt.Errorf("no nodes were parsed") + logger.Logger.ErrorContext(ctx, err.Error()) + return nil, err + } + + return parsedNodes, nil +} + +// isBase64 checks if the input string is a valid Base64 encoded string +func (tds *textDictionaryService) isBase64(s string) bool { + + // Base64 strings are generally divisible by 4 + if len(s)%4 != 0 { + return false + } + + // Check if the string contains only valid Base64 characters + for _, r := range s { + if !(unicode.IsLetter(r) || unicode.IsDigit(r) || strings.ContainsRune("+/=", r)) { + return false + } + } + + // Decode to verify it is actually Base64 encoded + _, err := base64.StdEncoding.DecodeString(s) + return err == nil +} + +// decodeBase64 decodes a Base64 encoded string +func (tds *textDictionaryService) decodeBase64(s string) (string, error) { + + decoded, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return "", err + } + return string(decoded), nil +} diff --git a/backend/pkg/textdic/parser_service_test.go b/backend/pkg/textdic/text_dictionary_service_test.go similarity index 71% rename from backend/pkg/textdic/parser_service_test.go rename to backend/pkg/textdic/text_dictionary_service_test.go index 2eb68d7..ef582c9 100644 --- a/backend/pkg/textdic/parser_service_test.go +++ b/backend/pkg/textdic/text_dictionary_service_test.go @@ -1,6 +1,7 @@ package textdic import ( + "golang.org/x/net/context" "sync" "testing" ) @@ -61,10 +62,11 @@ There is no leeway to provide services free of charge for the sake of others. t.Parallel() // Mark the test to run in parallel // Create a new parser service - service := NewParserService() + service := NewTextDictionaryService() + ctx := context.Background() // Process the dictionary input - parsedNodes, err := service.ProcessDictionary(tc.input) + parsedNodes, err := service.Process(ctx, tc.input) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -110,12 +112,13 @@ There is no leeway to provide services free of charge for the sake of others. tc := tc // capture range variable to avoid issues in parallel tests t.Run(tc.name, func(t *testing.T) { t.Parallel() // Mark the test to run in parallel + ctx := context.Background() // Create a new parser service - service := NewParserService() + service := NewTextDictionaryService() // Process the dictionary input - parsedNodes, err := service.ProcessDictionary(tc.input) + parsedNodes, err := service.Process(ctx, tc.input) if tc.wantErr { if err == nil { @@ -146,10 +149,11 @@ There is no leeway to provide services free of charge for the sake of others. defer wg.Done() // Create a new parser service - service := NewParserService() + service := NewTextDictionaryService() + ctx := context.Background() // Process the dictionary input - parsedNodes, err := service.ProcessDictionary(tc.input) + parsedNodes, err := service.Process(ctx, tc.input) if err != nil { t.Errorf("unexpected error: %v", err) return @@ -170,4 +174,71 @@ There is no leeway to provide services free of charge for the sake of others. wg.Wait() // Wait for all goroutines to finish } }) + + // Add tests for isBase64 and decodeBase64 + t.Run("Test_isBase64", func(t *testing.T) { + service := NewTextDictionaryService() + + // Define test cases + testCases := []struct { + name string + input string + expected bool + }{ + {"Valid Base64", "SGVsbG8gd29ybGQ=", true}, + {"Empty String", "", true}, + {"Invalid Base64", "Hello, World!", false}, + {"Invalid Characters", "SGVsbG8gd29ybGQ$#", false}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() // Mark the test to run in parallel + + result := service.isBase64(tc.input) + if result != tc.expected { + t.Errorf("expected %v, but got %v", tc.expected, result) + } + }) + } + }) + + t.Run("Test_decodeBase64", func(t *testing.T) { + service := NewTextDictionaryService() + + // Define test cases + testCases := []struct { + name string + input string + wantErr bool + expected string + }{ + {"Valid Base64", "SGVsbG8gd29ybGQ=", false, "Hello world"}, + {"Empty String", "", false, ""}, + {"Invalid Base64", "Hello, World!", true, ""}, + {"Invalid Base64 Hello World", "SGVsbG8aaagd29ybGQ", true, ""}, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() // Mark the test to run in parallel + + result, err := service.decodeBase64(tc.input) + if tc.wantErr { + if err == nil { + t.Errorf("expected error but got none") + } + } else { + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if result != tc.expected { + t.Errorf("expected %s, but got %s", tc.expected, result) + } + } + }) + } + }) }