diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml new file mode 100644 index 0000000..5feb40f --- /dev/null +++ b/.github/workflows/go-test.yml @@ -0,0 +1,34 @@ +on: + pull_request: + branches: + - master + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.23' + + - name: Cache Go modules + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Install dependencies + run: | + go mod download # Download modules + + - name: Run tests + run: go test -v ./... diff --git a/utils/helpers/helpers_test.go b/utils/helpers/helpers_test.go index cdcae9d..0296df3 100644 --- a/utils/helpers/helpers_test.go +++ b/utils/helpers/helpers_test.go @@ -44,6 +44,24 @@ func TestToFloat_NonNumericString(t *testing.T) { } } +func TestToFloat_StringWithOnlyCommas(t *testing.T) { + input := ",," + expected := 0.0 + result := ToFloat(input) + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestToFloat(t *testing.T) { + input := "-a%" + expected := 0.0 + result := ToFloat(input) + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + func TestCheckInstrumentName_Valid(t *testing.T) { input := "Name of the Instrument" result := CheckInstrumentName(input) @@ -52,6 +70,25 @@ func TestCheckInstrumentName_Valid(t *testing.T) { } } +func TestGetMarketCapCategory(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"20000", "Large Cap"}, + {"4999", "Small Cap"}, + {"15000", "Mid Cap"}, + } + + for _, test := range tests { + result := GetMarketCapCategory(test.input) + + if result != test.expected { + t.Errorf("Expected %v, got %v", test.expected, result) + } + } +} + func TestToStringArray_PrimitiveArray(t *testing.T) { input := primitive.A{"one", "two", "three"} result := ToStringArray(input) @@ -70,24 +107,6 @@ func TestToStringArray_InvalidInput(t *testing.T) { } } -func TestGetMarketCapCategory_LargeCap(t *testing.T) { - input := "20000" - expected := "Large Cap" - result := GetMarketCapCategory(input) - if result != expected { - t.Errorf("Expected %v, got %v", expected, result) - } -} - -func TestGetMarketCapCategory_SmallCap(t *testing.T) { - input := "4999" - expected := "Small Cap" - result := GetMarketCapCategory(input) - if result != expected { - t.Errorf("Expected %v, got %v", expected, result) - } -} - func TestToFloat_NonStringInput(t *testing.T) { input := 1234.56 expected := 0.0 @@ -97,15 +116,6 @@ func TestToFloat_NonStringInput(t *testing.T) { } } -func TestGetMarketCapCategory_MidCap(t *testing.T) { - input := "15000" - expected := "Mid Cap" - result := GetMarketCapCategory(input) - if result != expected { - t.Errorf("Expected %v, got %v", expected, result) - } -} - func TestMatchHeader_NormalizedStringMatch(t *testing.T) { patterns := []string{"^name of (the )?instrument$"} result := MatchHeader(" Name of the Instrument ", patterns) @@ -299,55 +309,6 @@ func TestNormalizeString_MixedCase(t *testing.T) { } } -func TestParsePeersTable(t *testing.T) { - html := ` - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
NamePEMarket CapDividend YieldROCE
Peer 110.080002.0%18.0
Peer 212.090002.2%19.0
-
- - ` - doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) - if err != nil { - t.Fatalf("Failed to create document: %v", err) - } - result := ParsePeersTable(doc, "#peers") - expected := []map[string]string{ - {"Name": "Peer 1", "PE": "10.0", "Market Cap": "8000", "Dividend Yield": "2.0%", "ROCE": "18.0"}, - {"Name": "Peer 2", "PE": "12.0", "Market Cap": "9000", "Dividend Yield": "2.2%", "ROCE": "19.0"}, - } - if !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %v, got %v", expected, result) - } -} - func TestFetchPeerData_InvalidID(t *testing.T) { _, err := FetchPeerData("invalidID") if err == nil { @@ -425,12 +386,13 @@ func TestParseTableData_MultipleRowsAndColumns(t *testing.T) { t.Errorf("Expected %v, got %v", expected, result) } } + func TestCalculateProfitabilityScore_MissingProfitLossField(t *testing.T) { - stock := map[string]interface{}{ - "balanceSheet": map[string]interface{}{ + stock := bson.M{ + "balanceSheet": bson.M{ "Total Assets": primitive.A{"1000", "2000"}, }, - "cashFlows": map[string]interface{}{ + "cashFlows": bson.M{ "Cash from Operating Activity +": primitive.A{"500", "600"}, }, } @@ -443,11 +405,11 @@ func TestCalculateProfitabilityScore_MissingProfitLossField(t *testing.T) { } func TestCalculateProfitabilityScore_MissingNetProfitField(t *testing.T) { - stock := map[string]interface{}{ - "balanceSheet": map[string]interface{}{ + stock := bson.M{ + "balanceSheet": bson.M{ "Total Assets": primitive.A{"5000", "6000"}, }, - "cashFlows": map[string]interface{}{ + "cashFlows": bson.M{ "Cash from Operating Activity +": primitive.A{"500", "600"}, }, } @@ -459,11 +421,11 @@ func TestCalculateProfitabilityScore_MissingNetProfitField(t *testing.T) { } func TestCalculateProfitabilityScore_MissingTotalAssetsField(t *testing.T) { - stock := map[string]interface{}{ - "profitLoss": map[string]interface{}{ - "Net Profit +": primitive.A{"1000", "2000"}, + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"1000", "2000"}, }, - "cashFlows": map[string]interface{}{ + "cashFlows": bson.M{ "Cash from Operating Activity +": primitive.A{"500", "600"}, }, } @@ -474,9 +436,71 @@ func TestCalculateProfitabilityScore_MissingTotalAssetsField(t *testing.T) { } } +func TestCalculateProfitabilityScore_MissingCashFromOperatingActivity(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{ + "5", "-2", "-2", + "11", "16", "19", + "25", "24", "23", + "35", "42", "56", + "59", + }, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{ + "294", "328", "333", + "334", "363", "376", + "404", "444", "452", + "514", "523", "588", + }, + }, + } + result := calculateProfitabilityScore(stock) + expected := -1 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestCalculateProfitabilityScore_CurrentCashOpsGreaterThanPrevious(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{ + "5", "-2", "-2", + "11", "16", "19", + "25", "24", "23", + "35", "42", "56", + "59", + }, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{ + "294", "328", "333", + "334", "363", "376", + "404", "444", "452", + "514", "523", "588", + }, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{ + "45", "37", "30", + "25", "44", "61", + "53", "45", "52", + "35", "63", "64", + }, + }, + } + result := calculateProfitabilityScore(stock) + expected := 4 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + func TestCalculateLeverageScore_MissingBorrowingsField(t *testing.T) { - stock := map[string]interface{}{ - "balanceSheet": map[string]interface{}{ + stock := bson.M{ + "balanceSheet": bson.M{ "Total Assets": primitive.A{"5000", "4000"}, "Other Assets +": primitive.A{"3000", "2500"}, "Other Liabilities +": primitive.A{"1000", "800"}, @@ -491,11 +515,43 @@ func TestCalculateLeverageScore_MissingBorrowingsField(t *testing.T) { } func TestCalculateLeverageScore_MissingTotalAssetsField(t *testing.T) { - stock := map[string]interface{}{ - "balanceSheet": map[string]interface{}{ - "Borrowings +": primitive.A{"2000", "1500"}, - "Other Assets +": primitive.A{"3000", "2500"}, - "Other Liabilities +": primitive.A{"1000", "800"}, + stock := bson.M{ + "balanceSheet": bson.M{ + "Borrowings\u00A0+": primitive.A{"5000", "4000"}, + "Other Assets\u00A0+": primitive.A{"3000", "2500"}, + "Other Liabilities\u00A0+": primitive.A{"1000", "800"}, + "Equity Capital": primitive.A{"1000", "1000"}, + }, + } + result := calculateLeverageScore(stock) + expected := -1 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestCalculateLeverageScore_MissingOtherAssets(t *testing.T) { + stock := bson.M{ + "balanceSheet": bson.M{ + "Borrowings\u00A0+": primitive.A{"5000", "4000"}, + "Total Assets": primitive.A{"3000", "2500"}, + "Other Liabilities\u00A0+": primitive.A{"1000", "800"}, + "Equity Capital": primitive.A{"1000", "1000"}, + }, + } + result := calculateLeverageScore(stock) + expected := -1 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestCalculateLeverageScore_MissingOtherLiabilities(t *testing.T) { + stock := bson.M{ + "balanceSheet": bson.M{ + "Borrowings\u00A0+": primitive.A{"5000", "4000"}, + "Total Assets": primitive.A{"3000", "2500"}, + "Other Assets\u00A0+": primitive.A{"1000", "800"}, "Equity Capital": primitive.A{"1000", "1000"}, }, } @@ -506,6 +562,22 @@ func TestCalculateLeverageScore_MissingTotalAssetsField(t *testing.T) { } } +func TestCalculateLeverageScore_MissingEquityCapital(t *testing.T) { + stock := bson.M{ + "balanceSheet": bson.M{ + "Borrowings\u00A0+": primitive.A{"5000", "4000"}, + "Total Assets": primitive.A{"3000", "2500"}, + "Other Assets\u00A0+": primitive.A{"1000", "800"}, + "Other Liabilities\u00A0+": primitive.A{"1000", "800"}, + }, + } + result := calculateLeverageScore(stock) + expected := -1 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + func TestGetNestedArrayField_ValidField(t *testing.T) { stock := map[string]interface{}{ "balanceSheet": bson.M{ @@ -534,6 +606,18 @@ func TestGetNestedArrayField_FieldNotFound(t *testing.T) { } } +func TestGetNestedArrayField_EmptyFields(t *testing.T) { + stock := map[string]interface{}{ + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"1000", "2000"}, + }, + } + _, err := getNestedArrayField(stock) + if err == nil { + t.Errorf("Expected error, got nil") + } +} + func TestGetNestedArrayField_NonStringElements(t *testing.T) { stock := map[string]interface{}{ "balanceSheet": bson.M{ @@ -558,6 +642,23 @@ func TestGetNestedArrayField_IncorrectPath(t *testing.T) { } } +func TestGetNestedArrayField_KeysWithPlus(t *testing.T) { + stock := map[string]interface{}{ + "balanceSheet": bson.M{ + "Other Liabilities\u00A0+": primitive.A{ + "22", "8", "20", "20", + "20", "18", "4", "2", + "2", "2", "7", "2", + }, + }, + } + + _, err := getNestedArrayField(stock, "balanceSheet", "Other Liabilities +") + if err != nil { + t.Error("Returned error ", err.Error()) + } +} + func TestFetchCompanyData_InvalidURL(t *testing.T) { _, err := FetchCompanyData("invalid-url") if err == nil { @@ -654,7 +755,59 @@ func TestParseTableData_CorrectParsing(t *testing.T) { if !reflect.DeepEqual(result, expected) { t.Errorf("Expected %v, got %v", expected, result) } +} + +func TestParseTableData_EmptyTable(t *testing.T) { + html := ` + + +
+ + + + + + + + + + +
Year20192020
+
+ + ` + + doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) + if err != nil { + t.Fatalf("Failed to create document: %v", err) + } + section := doc.Find("#data-section") + result := ParseTableData(section, "table") + expected := map[string]interface{}{} + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestParseTableData_NoTable(t *testing.T) { + html := ` + + +
+
+ + ` + + doc, err := goquery.NewDocumentFromReader(strings.NewReader(html)) + if err != nil { + t.Fatalf("Failed to create document: %v", err) + } + section := doc.Find("#data-section") + result := ParseTableData(section, "table") + if !reflect.ValueOf(result).IsNil() { + t.Errorf("Expected nil, got %v", result) + } } func TestRateStock_MissingFields(t *testing.T) { @@ -705,6 +858,25 @@ func TestAnalyzeTrend_ValidData(t *testing.T) { } } +func TestAnalyzeTrend_DecreasingTrend(t *testing.T) { + stock := types.Stock{ + Name: "Test Stock", + PE: 15.5, + MarketCap: 10000, + DividendYield: 2.5, + ROCE: 20.0, + } + pastData := bson.M{ + "Q1": primitive.A{bson.M{"sales": "1000", "profit": "100"}, bson.M{"sales": "1100", "profit": "110"}}, + "Q2": primitive.A{bson.M{"sales": "1200", "profit": "120"}, bson.M{"sales": "1300", "profit": "80"}}, + } + result := AnalyzeTrend(stock, pastData) + + if result == 0.0 { + t.Errorf("Expected non-zero trend score, got %v", result) + } +} + func TestCompareWithPeers_InsufficientPeers(t *testing.T) { stock := types.Stock{ Name: "Test Stock", @@ -719,5 +891,386 @@ func TestCompareWithPeers_InsufficientPeers(t *testing.T) { if result != expected { t.Errorf("Expected %v, got %v", expected, result) } +} + +func TestCompareWithPeers(t *testing.T) { + stock := types.Stock{ + Name: "Test Stock", + PE: 15.5, + MarketCap: 10000, + DividendYield: 2.5, + ROCE: 20.0, + QuarterlySales: 7000.0, + QuarterlyProfit: 2000.0, + } + peers := primitive.A{ + bson.M{ + "market_cap": "449311.45", + "div_yield": "0.74", + "qtr_sales_var": "5.96", + "roce": "17.32", + "name": "Sun Pharma.Inds.", + "current_price": "1872.65", + "pe": "42.57", + "np_qtr": "2860.51", + "qtr_profit_var": "25.05", + "sales_qtr": "12652.75", + }, + bson.M{ + "market_cap": "132360.30", + "div_yield": "0.79", + "qtr_profit_var": "18.05", + "sales_qtr": "6693.94", + "name": "Cipla", + "pe": "29.85", + "np_qtr": "1175.46", + "qtr_sales_var": "5.77", + "roce": "22.80", + "current_price": "1639.00", + }, + bson.M{ + "qtr_sales_var": "13.88", + "roce": "26.53", + "name": "Dr Reddy's Labs", + "pe": "19.93", + "div_yield": "0.60", + "np_qtr": "1392.40", + "qtr_profit_var": "-0.90", + "sales_qtr": "7696.10", + "current_price": "6638.40", + "market_cap": "110774.91", + }, + } + + result := compareWithPeers(stock, peers) + expected := 34.0 + if result != expected { + t.Errorf("Expected %v, got %v", expected, result) + } +} + +func TestCheckArrayElementsAreString_AllElementsAreString(t *testing.T) { + input := primitive.A{"all", "elements", "are", "string"} + expected := primitive.A{"all", "elements", "are", "string"} + + result, err := checkArrayElementsAreString(input) + if err != nil { + t.Error("Received error: ", err.Error()) + } + + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCheckArrayElementsAreString_AllElementsAreNotString(t *testing.T) { + input := primitive.A{"all", "elements", "are", 1, "string"} + expected := primitive.A{} + + result, err := checkArrayElementsAreString(input) + if err == nil { + t.Error("Expected error received nil") + } + + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestGenerateFScore_OnProfitabilityError(t *testing.T) { + stock := bson.M{ + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"1000", "2000"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity +": primitive.A{"500", "600"}, + }, + } + + result := GenerateFScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestGenerateFScore_OnLeverageScoreError(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5", "-2", "-2"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := GenerateFScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestGenerateFScore_OnOperatingEfficiencyError(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5", "-2", "-2"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := GenerateFScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestGenerateTestFScore_ValidInput(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{ + "5", "-2", "-2", + "11", "16", "19", + "25", "24", "23", + "35", "42", "56", + "59", + }, + "OPM %": primitive.A{ + "26%", "-19%", "-126%", + "-122%", "-73%", "-23%", + "-74%", "-71%", "-52%", + "-73%", "-9%", "21%", + "5%", + }, + "SalesĀ +": primitive.A{ + "752", "568", "210", + "205", "218", "322", + "261", "212", "160", + "160", "290", "472", + "396", + }, + "Revenue": primitive.A{ + "1,266", "1,388", "1,575", "1,728", "2,043", "2,587", + }, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{ + "294", "328", "333", + "334", "363", "376", + "404", "444", "452", + "514", "523", "588", + }, + "Borrowings\u00A0+": primitive.A{ + "1,464", "495", "486", + "509", "498", "101", + "4", "0", "0", + "0", "4", "5", + }, + "Other Assets\u00A0+": primitive.A{ + "2,193", "1,882", + "1,497", "1,263", + "1,386", "1,683", + "2,077", "2,121", + "2,120", "2,190", + "2,421", "2,633", + }, + "Other Liabilities\u00A0+": primitive.A{ + "1,408", "529", "548", + "327", "311", "287", + "275", "268", "251", + "272", "347", "293", + }, + "Equity Capital": primitive.A{ + "9", "9", "9", "9", + "9", "9", "9", "9", + "9", "9", "9", "9", + }, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{ + "45", "37", "30", + "25", "44", "61", + "53", "45", "52", + "35", "63", "54", + }, + }, + } + + result := GenerateFScore(stock) + expected := 6 + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_MissingNetProfit(t *testing.T) { + stock := bson.M{ + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_MissingRevenueWithSalesMissing(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5", "-2", "-2"}, + "OPM %": primitive.A{"26%", "-19%", "-126%"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_MissingSales(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5", "-2", "-2"}, + "OPM %": primitive.A{"26%", "-19%", "-126%"}, + "Revenue": primitive.A{"1,266", "1,388", "1,575"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := 1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_CurrentMarginGreaterThanPrevious(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5", "10", "-2"}, + "Revenue": primitive.A{"1,266", "1,388", "1,575"}, + "Sales\u00A0+": primitive.A{"752", "568", "210"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := 1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_ProfitAndRevenueLengthLessThan2(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5"}, + "Revenue": primitive.A{"1,266"}, + "Sales\u00A0+": primitive.A{"752", "568", "210"}, + }, + "balanceSheet": bson.M{ + "Total Assets": primitive.A{"294", "328", "333"}, + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := -1 + + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } +} + +func TestCalculateOperatingEfficiencyScore_TotalAssetsMissing(t *testing.T) { + stock := bson.M{ + "profitLoss": bson.M{ + "Net Profit\u00A0+": primitive.A{"5"}, + "Revenue": primitive.A{"1,266"}, + "OPM %": primitive.A{"26%", "-19%", "-126%"}, + "Sales\u00A0+": primitive.A{"752", "568", "210"}, + }, + "balanceSheet": bson.M{ + "Borrowings\u00A0+": primitive.A{"1,464", "495", "486"}, + "Other Assets\u00A0+": primitive.A{"2,193", "1,882", "1,497"}, + "Other Liabilities\u00A0+": primitive.A{"1,408", "529", "548"}, + "Equity Capital": primitive.A{"9", "9", "9", "9"}, + }, + "cashFlows": bson.M{ + "Cash from Operating Activity\u00A0+": primitive.A{"45", "37", "30"}, + }, + } + + result := calculateOperatingEfficiencyScore(stock) + expected := -1 + if result != expected { + t.Errorf("Expected %v got %v", expected, result) + } }