4
0

parser_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package config // import "miniflux.app/v2/internal/config"
  4. import (
  5. "net/url"
  6. "os"
  7. "reflect"
  8. "testing"
  9. "time"
  10. )
  11. func TestParseStringValue(t *testing.T) {
  12. // Test with non-empty value
  13. result := parseStringValue("test", "fallback")
  14. if result != "test" {
  15. t.Errorf("Expected 'test', got '%s'", result)
  16. }
  17. // Test with empty value
  18. result = parseStringValue("", "fallback")
  19. if result != "fallback" {
  20. t.Errorf("Expected 'fallback', got '%s'", result)
  21. }
  22. // Test with empty value and empty fallback
  23. result = parseStringValue("", "")
  24. if result != "" {
  25. t.Errorf("Expected empty string, got '%s'", result)
  26. }
  27. }
  28. func TestParseBoolValue(t *testing.T) {
  29. // Test with empty value - should return fallback
  30. result, err := parseBoolValue("", true)
  31. if err != nil {
  32. t.Errorf("Unexpected error: %v", err)
  33. }
  34. if result != true {
  35. t.Errorf("Expected true, got %v", result)
  36. }
  37. // Test true values
  38. trueValues := []string{"1", "yes", "true", "on", "YES", "TRUE", "ON"}
  39. for _, value := range trueValues {
  40. result, err := parseBoolValue(value, false)
  41. if err != nil {
  42. t.Errorf("Unexpected error for value '%s': %v", value, err)
  43. }
  44. if result != true {
  45. t.Errorf("Expected true for '%s', got %v", value, result)
  46. }
  47. }
  48. // Test false values
  49. falseValues := []string{"0", "no", "false", "off", "NO", "FALSE", "OFF"}
  50. for _, value := range falseValues {
  51. result, err := parseBoolValue(value, true)
  52. if err != nil {
  53. t.Errorf("Unexpected error for value '%s': %v", value, err)
  54. }
  55. if result != false {
  56. t.Errorf("Expected false for '%s', got %v", value, result)
  57. }
  58. }
  59. // Test invalid value - should return error
  60. _, err = parseBoolValue("invalid", false)
  61. if err == nil {
  62. t.Error("Expected error for invalid boolean value")
  63. }
  64. }
  65. func TestParseIntValue(t *testing.T) {
  66. // Test with empty value - should return fallback
  67. result := parseIntValue("", 42)
  68. if result != 42 {
  69. t.Errorf("Expected 42, got %d", result)
  70. }
  71. // Test with valid integer
  72. result = parseIntValue("123", 42)
  73. if result != 123 {
  74. t.Errorf("Expected 123, got %d", result)
  75. }
  76. // Test with invalid integer - should return fallback
  77. result = parseIntValue("invalid", 42)
  78. if result != 42 {
  79. t.Errorf("Expected 42, got %d", result)
  80. }
  81. // Test with zero
  82. result = parseIntValue("0", 42)
  83. if result != 0 {
  84. t.Errorf("Expected 0, got %d", result)
  85. }
  86. }
  87. func TestParsedInt64Value(t *testing.T) {
  88. // Test with empty value - should return fallback
  89. result := ParsedInt64Value("", 42)
  90. if result != 42 {
  91. t.Errorf("Expected 42, got %d", result)
  92. }
  93. // Test with valid int64
  94. result = ParsedInt64Value("9223372036854775807", 42)
  95. if result != 9223372036854775807 {
  96. t.Errorf("Expected 9223372036854775807, got %d", result)
  97. }
  98. // Test with invalid int64 - should return fallback
  99. result = ParsedInt64Value("invalid", 42)
  100. if result != 42 {
  101. t.Errorf("Expected 42, got %d", result)
  102. }
  103. }
  104. func TestParseStringListValue(t *testing.T) {
  105. // Test with empty value - should return fallback
  106. fallback := []string{"a", "b"}
  107. result := parseStringListValue("", fallback)
  108. if !reflect.DeepEqual(result, fallback) {
  109. t.Errorf("Expected %v, got %v", fallback, result)
  110. }
  111. // Test with single value
  112. result = parseStringListValue("item1", nil)
  113. expected := []string{"item1"}
  114. if !reflect.DeepEqual(result, expected) {
  115. t.Errorf("Expected %v, got %v", expected, result)
  116. }
  117. // Test with multiple values
  118. result = parseStringListValue("item1,item2,item3", nil)
  119. expected = []string{"item1", "item2", "item3"}
  120. if !reflect.DeepEqual(result, expected) {
  121. t.Errorf("Expected %v, got %v", expected, result)
  122. }
  123. // Test with duplicates - should remove duplicates
  124. result = parseStringListValue("item1,item2,item1", nil)
  125. expected = []string{"item1", "item2"}
  126. if !reflect.DeepEqual(result, expected) {
  127. t.Errorf("Expected %v, got %v", expected, result)
  128. }
  129. // Test with spaces
  130. result = parseStringListValue(" item1 , item2 , item3 ", nil)
  131. expected = []string{"item1", "item2", "item3"}
  132. if !reflect.DeepEqual(result, expected) {
  133. t.Errorf("Expected %v, got %v", expected, result)
  134. }
  135. }
  136. func TestParseDurationValue(t *testing.T) {
  137. // Test with empty value - should return fallback
  138. fallback := 5 * time.Second
  139. result := parseDurationValue("", time.Second, fallback)
  140. if result != fallback {
  141. t.Errorf("Expected %v, got %v", fallback, result)
  142. }
  143. // Test with valid duration
  144. result = parseDurationValue("30", time.Second, fallback)
  145. expected := 30 * time.Second
  146. if result != expected {
  147. t.Errorf("Expected %v, got %v", expected, result)
  148. }
  149. // Test with minutes
  150. result = parseDurationValue("5", time.Minute, fallback)
  151. expected = 5 * time.Minute
  152. if result != expected {
  153. t.Errorf("Expected %v, got %v", expected, result)
  154. }
  155. // Test with invalid value - should return fallback
  156. result = parseDurationValue("invalid", time.Second, fallback)
  157. if result != fallback {
  158. t.Errorf("Expected %v, got %v", fallback, result)
  159. }
  160. }
  161. func TestParseURLValue(t *testing.T) {
  162. // Test with empty value - should return fallback
  163. fallbackURL, _ := url.Parse("https://fallback.com")
  164. result, err := parseURLValue("", fallbackURL)
  165. if err != nil {
  166. t.Errorf("Unexpected error: %v", err)
  167. }
  168. if result != fallbackURL {
  169. t.Errorf("Expected %v, got %v", fallbackURL, result)
  170. }
  171. // Test with valid URL
  172. result, err = parseURLValue("https://example.com", nil)
  173. if err != nil {
  174. t.Errorf("Unexpected error: %v", err)
  175. }
  176. if result.String() != "https://example.com" {
  177. t.Errorf("Expected https://example.com, got %s", result.String())
  178. }
  179. // Test with invalid URL - should return fallback and error
  180. result, err = parseURLValue("://invalid", fallbackURL)
  181. if err == nil {
  182. t.Error("Expected error for invalid URL")
  183. }
  184. if result != fallbackURL {
  185. t.Errorf("Expected fallback URL, got %v", result)
  186. }
  187. }
  188. func TestConfigFileParsing(t *testing.T) {
  189. fileContent := `
  190. # This is a comment
  191. LOG_FILE=miniflux.log
  192. LOG_DATE_TIME=1
  193. LOG_FORMAT=json
  194. LISTEN_ADDR=:8080,:8443
  195. `
  196. // Write a temporary config file and parse it
  197. tmpFile, err := os.CreateTemp("", "miniflux-*.txt")
  198. if err != nil {
  199. t.Fatalf("Failed to create temporary file: %v", err)
  200. }
  201. defer os.Remove(tmpFile.Name())
  202. defer tmpFile.Close()
  203. filename := tmpFile.Name()
  204. if _, err := tmpFile.WriteString(fileContent); err != nil {
  205. t.Fatalf("Failed to write to temporary file: %v", err)
  206. }
  207. configParser := NewConfigParser()
  208. configOptions, err := configParser.ParseFile(filename)
  209. if err != nil {
  210. t.Fatalf("Unexpected parsing error: %v", err)
  211. }
  212. if configOptions.LogFile() != "miniflux.log" {
  213. t.Fatalf("Unexpected log file, got %q", configOptions.LogFile())
  214. }
  215. if configOptions.LogDateTime() != true {
  216. t.Fatalf("Unexpected log datetime, got %v", configOptions.LogDateTime())
  217. }
  218. if configOptions.LogFormat() != "json" {
  219. t.Fatalf("Unexpected log format, got %q", configOptions.LogFormat())
  220. }
  221. if configOptions.LogLevel() != "info" {
  222. t.Fatalf("Unexpected log level, got %q", configOptions.LogLevel())
  223. }
  224. if len(configOptions.ListenAddr()) != 2 || configOptions.ListenAddr()[0] != ":8080" || configOptions.ListenAddr()[1] != ":8443" {
  225. t.Fatalf("Unexpected listen addresses, got %v", configOptions.ListenAddr())
  226. }
  227. }
  228. func TestConfigFileParsingWithIncorrectKeyValuePair(t *testing.T) {
  229. fileContent := `
  230. LOG_FILE=miniflux.log
  231. INVALID_LINE
  232. `
  233. // Write a temporary config file and parse it
  234. tmpFile, err := os.CreateTemp("", "miniflux-*.txt")
  235. if err != nil {
  236. t.Fatalf("Failed to create temporary file: %v", err)
  237. }
  238. defer os.Remove(tmpFile.Name())
  239. defer tmpFile.Close()
  240. filename := tmpFile.Name()
  241. if _, err := tmpFile.WriteString(fileContent); err != nil {
  242. t.Fatalf("Failed to write to temporary file: %v", err)
  243. }
  244. configParser := NewConfigParser()
  245. _, err = configParser.ParseFile(filename)
  246. if err != nil {
  247. t.Fatal("Invalid lines should be ignored, but got error:", err)
  248. }
  249. }
  250. func TestParseAdminPasswordFileOption(t *testing.T) {
  251. tmpFile, err := os.CreateTemp("", "password-*.txt")
  252. if err != nil {
  253. t.Fatalf("Failed to create temporary file: %v", err)
  254. }
  255. defer os.Remove(tmpFile.Name())
  256. defer tmpFile.Close()
  257. password := "supersecret"
  258. if _, err := tmpFile.WriteString(password); err != nil {
  259. t.Fatalf("Failed to write to temporary file: %v", err)
  260. }
  261. os.Clearenv()
  262. os.Setenv("ADMIN_PASSWORD_FILE", tmpFile.Name())
  263. configParser := NewConfigParser()
  264. configOptions, err := configParser.ParseEnvironmentVariables()
  265. if err != nil {
  266. t.Fatalf("Unexpected parsing error: %v", err)
  267. }
  268. if configOptions.AdminPassword() != password {
  269. t.Fatalf("Unexpected admin password, got %q", configOptions.AdminPassword())
  270. }
  271. }
  272. func TestParseAdminPasswordFileOptionWithEmptyFile(t *testing.T) {
  273. tmpFile, err := os.CreateTemp("", "empty-password-*.txt")
  274. if err != nil {
  275. t.Fatalf("Failed to create temporary file: %v", err)
  276. }
  277. defer os.Remove(tmpFile.Name())
  278. defer tmpFile.Close()
  279. os.Clearenv()
  280. os.Setenv("ADMIN_PASSWORD_FILE", tmpFile.Name())
  281. configParser := NewConfigParser()
  282. _, err = configParser.ParseEnvironmentVariables()
  283. if err == nil {
  284. t.Fatal("Expected error due to empty password file, but got none")
  285. }
  286. }
  287. func TestParseLogFileOptionDefaultValue(t *testing.T) {
  288. os.Clearenv()
  289. configParser := NewConfigParser()
  290. configOptions, err := configParser.ParseEnvironmentVariables()
  291. if err != nil {
  292. t.Fatalf("Unexpected parsing error: %v", err)
  293. }
  294. if configOptions.LogFile() != "stderr" {
  295. t.Fatalf("Unexpected default log file, got %q", configOptions.LogFile())
  296. }
  297. }
  298. func TestParseLogFileOptionWithCustomFilename(t *testing.T) {
  299. os.Clearenv()
  300. os.Setenv("LOG_FILE", "miniflux.log")
  301. configParser := NewConfigParser()
  302. configOptions, err := configParser.ParseEnvironmentVariables()
  303. if err != nil {
  304. t.Fatalf("Unexpected parsing error: %v", err)
  305. }
  306. if configOptions.LogFile() != "miniflux.log" {
  307. t.Fatalf("Unexpected log file, got %q", configOptions.LogFile())
  308. }
  309. }
  310. func TestParseLogFileOptionWithEmptyValue(t *testing.T) {
  311. os.Clearenv()
  312. os.Setenv("LOG_FILE", "")
  313. configParser := NewConfigParser()
  314. configOptions, err := configParser.ParseEnvironmentVariables()
  315. if err != nil {
  316. t.Fatalf("Unexpected parsing error: %v", err)
  317. }
  318. if configOptions.LogFile() != "stderr" {
  319. t.Fatalf("Unexpected log file, got %q", configOptions.LogFile())
  320. }
  321. }
  322. func TestParseLogDateTimeOptionDefaultValue(t *testing.T) {
  323. os.Clearenv()
  324. configParser := NewConfigParser()
  325. configOptions, err := configParser.ParseEnvironmentVariables()
  326. if err != nil {
  327. t.Fatalf("Unexpected parsing error: %v", err)
  328. }
  329. if configOptions.LogDateTime() != false {
  330. t.Fatalf("Unexpected default log datetime, got %v", configOptions.LogDateTime())
  331. }
  332. }
  333. func TestParseLogDateTimeOptionWithCustomValue(t *testing.T) {
  334. os.Clearenv()
  335. os.Setenv("LOG_DATE_TIME", "true")
  336. configParser := NewConfigParser()
  337. configOptions, err := configParser.ParseEnvironmentVariables()
  338. if err != nil {
  339. t.Fatalf("Unexpected parsing error: %v", err)
  340. }
  341. if configOptions.LogDateTime() != true {
  342. t.Fatalf("Unexpected log datetime, got %v", configOptions.LogDateTime())
  343. }
  344. }
  345. func TestParseLogDateTimeOptionWithEmptyValue(t *testing.T) {
  346. os.Clearenv()
  347. os.Setenv("LOG_DATE_TIME", "")
  348. configParser := NewConfigParser()
  349. configOptions, err := configParser.ParseEnvironmentVariables()
  350. if err != nil {
  351. t.Fatalf("Unexpected parsing error: %v", err)
  352. }
  353. if configOptions.LogDateTime() != false {
  354. t.Fatalf("Unexpected log datetime, got %v", configOptions.LogDateTime())
  355. }
  356. }
  357. func TestParseLogDateTimeOptionWithIncorrectValue(t *testing.T) {
  358. os.Clearenv()
  359. os.Setenv("LOG_DATE_TIME", "invalid")
  360. configParser := NewConfigParser()
  361. if _, err := configParser.ParseEnvironmentVariables(); err == nil {
  362. t.Fatal("Expected parsing error, got nil")
  363. }
  364. }