from abc import ABC, abstractmethod
import unittest

class IStringCalculator(ABC):
    @abstractmethod
    def add(self, numbers: str) -> int:
        pass

class StringCalculator(IStringCalculator):
    def add(self, numbers: str) -> int:
        if not numbers:
            return 0
        
        # Überprüfe, ob ein benutzerdefiniertes Trennzeichen angegeben ist
        if numbers.startswith("//"):
            delimiter_line_end = numbers.find("\n")
            delimiter = numbers[2:delimiter_line_end]  # Extrahiere das Trennzeichen
            numbers = numbers[delimiter_line_end + 1:]  # Entferne die erste Zeile mit dem Trennzeichen
            
        else:
            delimiter = ','  # Standard-Trennzeichen ist Komma, wenn keine Zeile mit dem Trennzeichen vorhanden ist

        # Ersetze alle Vorkommen des Trennzeichens und teile die Eingabe
        numbers = numbers.replace("\n", delimiter)
        nums = numbers.split(delimiter)
        
        # Prüfe auf negative Zahlen
        negatives = [num for num in nums if int(num) < 0]
        
        if negatives:
            # Wenn negative Zahlen vorhanden sind, werfe eine Ausnahme
            raise ValueError(f"Negatives not allowed: {', '.join(negatives)}")
        
        # Berechne die Summe der positiven Zahlen
        return sum(map(int, nums))

class TestStringCalculator(unittest.TestCase):
    def setUp(self):
        self.calculator = StringCalculator()
    
    def test_empty_string(self):
        self.assertEqual(self.calculator.add(""), 0)
    
    def test_single_number(self):
        self.assertEqual(self.calculator.add("1"), 1)
    
    def test_two_numbers(self):
        self.assertEqual(self.calculator.add("1,2"), 3)
    
    def test_multiple_numbers(self):
        self.assertEqual(self.calculator.add("1,2,3,4,5"), 15)
    
    def test_numbers_with_newline(self):
        self.assertEqual(self.calculator.add("1\n2,3"), 6)
    
    def test_numbers_with_multiple_newlines(self):
        self.assertEqual(self.calculator.add("1\n2\n3\n4\n5"), 15)
    
    def test_negative_number(self):
        with self.assertRaises(ValueError) as context:
            self.calculator.add("1,-2,3")
        self.assertEqual(str(context.exception), "Negatives not allowed: -2")
    
    def test_multiple_negative_numbers(self):
        with self.assertRaises(ValueError) as context:
            self.calculator.add("1,-2,-3,4")
        self.assertEqual(str(context.exception), "Negatives not allowed: -2, -3")
    
    def test_custom_delimiter(self):
        self.assertEqual(self.calculator.add("//;\n1;2"), 3)
    
    def test_custom_delimiter_with_newline(self):
        self.assertEqual(self.calculator.add("//;\n1;2\n3"), 6)
    
    def test_custom_delimiter_with_multiple_numbers(self):
        self.assertEqual(self.calculator.add("//|\n1|2|3|4"), 10)

if __name__ == "__main__":
    unittest.main()