mirror of
				https://github.com/shokinn/hosts-go.git
				synced 2025-11-04 04:28:34 +00:00 
			
		
		
		
	feat(parser): Implement hosts file parser with intelligent formatting
- Added `internal/core/parser.go` for parsing hosts files, including: - Support for standard entries (IPv4, IPv6, multiple aliases, inline comments) - Handling of comments and disabled entries - Error recovery for malformed lines with warnings - Intelligent formatting with adaptive spacing and column alignment - Backup and atomic write operations for file safety test(parser): Add comprehensive tests for hosts file parsing - Created `tests/parser_test.go` with 54 test cases covering: - Standard entries and comments - Malformed lines and whitespace variations - Round-trip parsing to ensure format preservation - Backup functionality for hosts files docs(progress): Update project progress and next steps - Mark Phase 1 as complete and outline tasks for Phase 2 (TUI implementation) - Highlight completed features and testing coverage
This commit is contained in:
		
							parent
							
								
									d66ec51ebd
								
							
						
					
					
						commit
						b81f11f711
					
				
					 10 changed files with 1303 additions and 210 deletions
				
			
		
							
								
								
									
										434
									
								
								tests/parser_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										434
									
								
								tests/parser_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,434 @@
 | 
			
		|||
package tests
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"hosts-go/internal/core"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"github.com/stretchr/testify/require"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParseHostsFile_StandardEntries(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name        string
 | 
			
		||||
		content     string
 | 
			
		||||
		expectedLen int
 | 
			
		||||
		checks      func(t *testing.T, hostsFile *core.HostsFile, warnings []core.ParseWarning)
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "basic IPv4 entry",
 | 
			
		||||
			content: `127.0.0.1	localhost`,
 | 
			
		||||
			expectedLen: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "127.0.0.1", entry.IP)
 | 
			
		||||
				assert.Equal(t, "localhost", entry.Hostname)
 | 
			
		||||
				assert.Empty(t, entry.Aliases)
 | 
			
		||||
				assert.True(t, entry.Active)
 | 
			
		||||
				assert.Empty(t, entry.Comment)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "entry with multiple aliases",
 | 
			
		||||
			content: `192.168.1.100	example.com	www.example.com	api.example.com`,
 | 
			
		||||
			expectedLen: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "192.168.1.100", entry.IP)
 | 
			
		||||
				assert.Equal(t, "example.com", entry.Hostname)
 | 
			
		||||
				assert.Equal(t, []string{"www.example.com", "api.example.com"}, entry.Aliases)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "entry with inline comment",
 | 
			
		||||
			content: `127.0.0.1	localhost	# Local loopback`,
 | 
			
		||||
			expectedLen: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "127.0.0.1", entry.IP)
 | 
			
		||||
				assert.Equal(t, "localhost", entry.Hostname)
 | 
			
		||||
				assert.Equal(t, "Local loopback", entry.Comment)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "IPv6 entry",
 | 
			
		||||
			content: `::1	localhost`,
 | 
			
		||||
			expectedLen: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "::1", entry.IP)
 | 
			
		||||
				assert.Equal(t, "localhost", entry.Hostname)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "multiple entries",
 | 
			
		||||
			content: `127.0.0.1	localhost
 | 
			
		||||
192.168.1.100	example.com
 | 
			
		||||
::1	ip6-localhost`,
 | 
			
		||||
			expectedLen: 3,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				assert.Equal(t, "127.0.0.1", hf.Entries[0].IP)
 | 
			
		||||
				assert.Equal(t, "192.168.1.100", hf.Entries[1].IP)
 | 
			
		||||
				assert.Equal(t, "::1", hf.Entries[2].IP)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			hostsFile, warnings, err := parseHostsContent(tt.content)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			assert.Len(t, hostsFile.Entries, tt.expectedLen)
 | 
			
		||||
			tt.checks(t, hostsFile, warnings)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseHostsFile_CommentsAndDisabled(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name         string
 | 
			
		||||
		content      string
 | 
			
		||||
		expectedEntries int
 | 
			
		||||
		expectedComments int
 | 
			
		||||
		checks       func(t *testing.T, hostsFile *core.HostsFile, warnings []core.ParseWarning)
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "disabled entry (commented out)",
 | 
			
		||||
			content: `# 192.168.1.100	disabled.com`,
 | 
			
		||||
			expectedEntries: 1,
 | 
			
		||||
			expectedComments: 0,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "192.168.1.100", entry.IP)
 | 
			
		||||
				assert.Equal(t, "disabled.com", entry.Hostname)
 | 
			
		||||
				assert.False(t, entry.Active)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "standalone comment",
 | 
			
		||||
			content: `# This is a comment line`,
 | 
			
		||||
			expectedEntries: 0,
 | 
			
		||||
			expectedComments: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				assert.Contains(t, hf.Comments, "This is a comment line")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "mixed active, disabled, and comments",
 | 
			
		||||
			content: `# Header comment
 | 
			
		||||
127.0.0.1	localhost
 | 
			
		||||
# 192.168.1.100	disabled.com	# disabled server
 | 
			
		||||
192.168.1.101	active.com
 | 
			
		||||
# Another comment`,
 | 
			
		||||
			expectedEntries: 3,
 | 
			
		||||
			expectedComments: 2,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
				
 | 
			
		||||
				// Check entries
 | 
			
		||||
				assert.True(t, hf.Entries[0].Active)  // localhost
 | 
			
		||||
				assert.False(t, hf.Entries[1].Active) // disabled.com
 | 
			
		||||
				assert.True(t, hf.Entries[2].Active)  // active.com
 | 
			
		||||
				
 | 
			
		||||
				// Check comments
 | 
			
		||||
				assert.Contains(t, hf.Comments, "Header comment")
 | 
			
		||||
				assert.Contains(t, hf.Comments, "Another comment")
 | 
			
		||||
				
 | 
			
		||||
				// Check disabled entry has comment
 | 
			
		||||
				assert.Equal(t, "disabled server", hf.Entries[1].Comment)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			hostsFile, warnings, err := parseHostsContent(tt.content)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			assert.Len(t, hostsFile.Entries, tt.expectedEntries)
 | 
			
		||||
			assert.Len(t, hostsFile.Comments, tt.expectedComments)
 | 
			
		||||
			tt.checks(t, hostsFile, warnings)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseHostsFile_MalformedLines(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name             string
 | 
			
		||||
		content          string
 | 
			
		||||
		expectedEntries  int
 | 
			
		||||
		expectedWarnings int
 | 
			
		||||
		checks           func(t *testing.T, hostsFile *core.HostsFile, warnings []core.ParseWarning)
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "invalid IP address",
 | 
			
		||||
			content: `999.999.999.999	invalid-ip.com`,
 | 
			
		||||
			expectedEntries: 0,
 | 
			
		||||
			expectedWarnings: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Contains(t, warnings[0].Message, "invalid IP address")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "missing hostname",
 | 
			
		||||
			content: `192.168.1.100`,
 | 
			
		||||
			expectedEntries: 0,
 | 
			
		||||
			expectedWarnings: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Contains(t, warnings[0].Message, "missing hostname")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "invalid hostname format",
 | 
			
		||||
			content: `192.168.1.100	-invalid-hostname.com`,
 | 
			
		||||
			expectedEntries: 0,
 | 
			
		||||
			expectedWarnings: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Contains(t, warnings[0].Message, "invalid hostname")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "mixed valid and invalid entries",
 | 
			
		||||
			content: `127.0.0.1	localhost
 | 
			
		||||
999.999.999.999	invalid.com
 | 
			
		||||
192.168.1.100	valid.com`,
 | 
			
		||||
			expectedEntries: 2,
 | 
			
		||||
			expectedWarnings: 1,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Equal(t, "localhost", hf.Entries[0].Hostname)
 | 
			
		||||
				assert.Equal(t, "valid.com", hf.Entries[1].Hostname)
 | 
			
		||||
				assert.Contains(t, warnings[0].Message, "invalid IP address")
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			hostsFile, warnings, err := parseHostsContent(tt.content)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			assert.Len(t, hostsFile.Entries, tt.expectedEntries)
 | 
			
		||||
			assert.Len(t, warnings, tt.expectedWarnings)
 | 
			
		||||
			if len(warnings) > 0 {
 | 
			
		||||
				tt.checks(t, hostsFile, warnings)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseHostsFile_WhitespaceVariations(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name    string
 | 
			
		||||
		content string
 | 
			
		||||
		checks  func(t *testing.T, hostsFile *core.HostsFile)
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "tabs and spaces mixed",
 | 
			
		||||
			content: "127.0.0.1\tlocalhost   \t# comment",
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile) {
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "127.0.0.1", entry.IP)
 | 
			
		||||
				assert.Equal(t, "localhost", entry.Hostname)
 | 
			
		||||
				assert.Equal(t, "comment", entry.Comment)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "leading and trailing whitespace",
 | 
			
		||||
			content: "   127.0.0.1   localhost   ",
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile) {
 | 
			
		||||
				entry := hf.Entries[0]
 | 
			
		||||
				assert.Equal(t, "127.0.0.1", entry.IP)
 | 
			
		||||
				assert.Equal(t, "localhost", entry.Hostname)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "empty lines",
 | 
			
		||||
			content: `127.0.0.1	localhost
 | 
			
		||||
 | 
			
		||||
192.168.1.100	example.com
 | 
			
		||||
 | 
			
		||||
`,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile) {
 | 
			
		||||
				assert.Len(t, hf.Entries, 2)
 | 
			
		||||
				assert.Equal(t, "localhost", hf.Entries[0].Hostname)
 | 
			
		||||
				assert.Equal(t, "example.com", hf.Entries[1].Hostname)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			hostsFile, warnings, err := parseHostsContent(tt.content)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			assert.Len(t, warnings, 0)
 | 
			
		||||
			tt.checks(t, hostsFile)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDetectFormattingStyle(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		content        string
 | 
			
		||||
		expectedUseTabs bool
 | 
			
		||||
		expectedSpaces  int
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "tab-separated content",
 | 
			
		||||
			content: `127.0.0.1	localhost
 | 
			
		||||
192.168.1.100	example.com`,
 | 
			
		||||
			expectedUseTabs: true,
 | 
			
		||||
			expectedSpaces: 0,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "space-separated content",
 | 
			
		||||
			content: `127.0.0.1       localhost
 | 
			
		||||
192.168.1.100   example.com`,
 | 
			
		||||
			expectedUseTabs: false,
 | 
			
		||||
			expectedSpaces: 4,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "mixed content (should default to tabs)",
 | 
			
		||||
			content: `127.0.0.1	localhost
 | 
			
		||||
192.168.1.100   example.com`,
 | 
			
		||||
			expectedUseTabs: true,
 | 
			
		||||
			expectedSpaces: 0,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			style := core.DetectFormattingStyle(strings.Split(tt.content, "\n"))
 | 
			
		||||
			assert.Equal(t, tt.expectedUseTabs, style.UseTabs)
 | 
			
		||||
			if !tt.expectedUseTabs {
 | 
			
		||||
				assert.Equal(t, tt.expectedSpaces, style.SpacesPerTab)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWriteHostsFile_RoundTrip(t *testing.T) {
 | 
			
		||||
	originalContent := `# Header comment
 | 
			
		||||
127.0.0.1	localhost	# Local loopback
 | 
			
		||||
192.168.1.100	example.com	www.example.com	# Development server
 | 
			
		||||
# 10.0.0.50	staging.com	# Disabled staging server
 | 
			
		||||
# Another comment`
 | 
			
		||||
 | 
			
		||||
	// Parse the content
 | 
			
		||||
	hostsFile, warnings, err := parseHostsContent(originalContent)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	assert.Len(t, warnings, 0)
 | 
			
		||||
 | 
			
		||||
	// Write it back and verify structure is preserved
 | 
			
		||||
	lines := core.FormatHostsFile(hostsFile)
 | 
			
		||||
	reformattedContent := strings.Join(lines, "\n")
 | 
			
		||||
 | 
			
		||||
	// Parse again to verify round-trip
 | 
			
		||||
	hostsFile2, warnings2, err2 := parseHostsContent(reformattedContent)
 | 
			
		||||
	require.NoError(t, err2)
 | 
			
		||||
	assert.Len(t, warnings2, 0)
 | 
			
		||||
 | 
			
		||||
	// Verify same number of entries and comments
 | 
			
		||||
	assert.Len(t, hostsFile2.Entries, len(hostsFile.Entries))
 | 
			
		||||
	assert.Len(t, hostsFile2.Comments, len(hostsFile.Comments))
 | 
			
		||||
 | 
			
		||||
	// Verify entry content matches
 | 
			
		||||
	for i, entry := range hostsFile.Entries {
 | 
			
		||||
		entry2 := hostsFile2.Entries[i]
 | 
			
		||||
		assert.Equal(t, entry.IP, entry2.IP)
 | 
			
		||||
		assert.Equal(t, entry.Hostname, entry2.Hostname)
 | 
			
		||||
		assert.Equal(t, entry.Aliases, entry2.Aliases)
 | 
			
		||||
		assert.Equal(t, entry.Comment, entry2.Comment)
 | 
			
		||||
		assert.Equal(t, entry.Active, entry2.Active)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseHostsFile_EmptyAndCommentOnlyFiles(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name    string
 | 
			
		||||
		content string
 | 
			
		||||
		checks  func(t *testing.T, hostsFile *core.HostsFile, warnings []core.ParseWarning)
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:    "completely empty file",
 | 
			
		||||
			content: "",
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, hf.Entries, 0)
 | 
			
		||||
				assert.Len(t, hf.Comments, 0)
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "only whitespace",
 | 
			
		||||
			content: `   
 | 
			
		||||
	
 | 
			
		||||
   `,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, hf.Entries, 0)
 | 
			
		||||
				assert.Len(t, hf.Comments, 0)
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "only comments",
 | 
			
		||||
			content: `# First comment
 | 
			
		||||
# Second comment
 | 
			
		||||
# Third comment`,
 | 
			
		||||
			checks: func(t *testing.T, hf *core.HostsFile, warnings []core.ParseWarning) {
 | 
			
		||||
				assert.Len(t, hf.Entries, 0)
 | 
			
		||||
				assert.Len(t, hf.Comments, 3)
 | 
			
		||||
				assert.Contains(t, hf.Comments, "First comment")
 | 
			
		||||
				assert.Contains(t, hf.Comments, "Second comment")
 | 
			
		||||
				assert.Contains(t, hf.Comments, "Third comment")
 | 
			
		||||
				assert.Len(t, warnings, 0)
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			hostsFile, warnings, err := parseHostsContent(tt.content)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			tt.checks(t, hostsFile, warnings)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBackupHostsFile(t *testing.T) {
 | 
			
		||||
	// Create a temporary file to simulate /etc/hosts
 | 
			
		||||
	tmpDir := t.TempDir()
 | 
			
		||||
	hostsPath := filepath.Join(tmpDir, "hosts")
 | 
			
		||||
	hostsContent := `127.0.0.1	localhost
 | 
			
		||||
192.168.1.100	example.com`
 | 
			
		||||
 | 
			
		||||
	err := os.WriteFile(hostsPath, []byte(hostsContent), 0644)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	// Test backup functionality
 | 
			
		||||
	backupPath, err := core.BackupHostsFile(hostsPath)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	assert.True(t, strings.Contains(backupPath, "hosts.backup"))
 | 
			
		||||
 | 
			
		||||
	// Verify backup file exists and has same content
 | 
			
		||||
	backupContent, err := os.ReadFile(backupPath)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, hostsContent, string(backupContent))
 | 
			
		||||
 | 
			
		||||
	// Cleanup
 | 
			
		||||
	os.Remove(backupPath)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function to parse hosts content from string (for testing)
 | 
			
		||||
func parseHostsContent(content string) (*core.HostsFile, []core.ParseWarning, error) {
 | 
			
		||||
	lines := strings.Split(content, "\n")
 | 
			
		||||
	return core.ParseHostsContent(lines)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue