2019-11-29 06:59:40 -05:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
2018-05-09 12:25:03 -04:00
package app
import (
"testing"
"github.com/avct/uasurfer"
2019-09-20 10:53:48 -04:00
"github.com/stretchr/testify/assert"
2018-05-09 12:25:03 -04:00
)
type testUserAgent struct {
2026-01-29 13:12:35 -05:00
Name string
UserAgent string
ExpectedPlatformName string
ExpectedOSName string
ExpectedBrowserName string
ExpectedBrowserVersion string
2018-05-09 12:25:03 -04:00
}
var testUserAgents = [ ] testUserAgent {
2026-01-29 13:12:35 -05:00
{
Name : "Mozilla 40.1" ,
UserAgent : "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 7" ,
ExpectedBrowserName : "Firefox" ,
ExpectedBrowserVersion : "40.1" ,
} ,
{
Name : "Chrome 60" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Chrome" ,
ExpectedBrowserVersion : "60.0.3112" ,
} ,
{
Name : "Chrome Mobile" ,
UserAgent : "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Mobile Safari/537.36" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Chrome" ,
ExpectedBrowserVersion : "60.0.3112" ,
} ,
{
Name : "MM Classic App" ,
UserAgent : "Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR6.170623.013; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.81 Mobile Safari/537.36 Web-Atoms-Mobile-WebView" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Chrome" ,
ExpectedBrowserVersion : "61.0.3163" ,
} ,
{
Name : "mmctl" ,
UserAgent : "mmctl/5.20.0 (linux)" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Linux" ,
ExpectedBrowserName : "mmctl" ,
ExpectedBrowserVersion : "5.20.0" ,
} ,
{
Name : "MM App 3.7.1" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Mattermost/3.7.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Desktop App" ,
ExpectedBrowserVersion : "3.7.1" ,
} ,
{
Name : "Franz 4.0.4" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/4.0.4 Chrome/52.0.2743.82 Electron/1.3.1 Safari/537.36" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Desktop App" ,
ExpectedBrowserVersion : "4.0.4" ,
} ,
{
Name : "Edge 14" ,
UserAgent : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 10" ,
ExpectedBrowserName : "Edge" ,
ExpectedBrowserVersion : "14.14393" ,
} ,
{
Name : "Internet Explorer 9" ,
UserAgent : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows" ,
ExpectedBrowserName : "Internet Explorer" ,
ExpectedBrowserVersion : "9.0" ,
} ,
{
Name : "Internet Explorer 11" ,
UserAgent : "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 10" ,
ExpectedBrowserName : "Internet Explorer" ,
ExpectedBrowserVersion : "11.0" ,
} ,
{
Name : "Internet Explorer 11 2" ,
UserAgent : "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0; rv:11.0) like Gecko" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 10" ,
ExpectedBrowserName : "Internet Explorer" ,
ExpectedBrowserVersion : "11.0" ,
} ,
{
Name : "Internet Explorer 11 (Compatibility Mode) 1" ,
UserAgent : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET CLR 1.1.4322; InfoPath.3; Zoom 3.6.0)" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 10" ,
ExpectedBrowserName : "Internet Explorer" ,
ExpectedBrowserVersion : "7.0" ,
} ,
{
Name : "Internet Explorer 11 (Compatibility Mode) 2" ,
UserAgent : "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Zoom 3.6.0)" ,
ExpectedPlatformName : "Windows" ,
ExpectedOSName : "Windows 10" ,
ExpectedBrowserName : "Internet Explorer" ,
ExpectedBrowserVersion : "7.0" ,
} ,
{
Name : "Safari 9" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Safari/604.1.38" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "11.0" ,
} ,
{
Name : "Safari 8" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "8.0.7" ,
} ,
{
Name : "Safari Mobile" ,
UserAgent : "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1" ,
ExpectedPlatformName : "iPhone" ,
ExpectedOSName : "iOS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "9.0" ,
} ,
{
Name : "Mobile App" ,
UserAgent : "Mattermost Mobile/2.7.0+482 (Android; 13; sdk_gphone64_arm64)" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "2.7.0+482" ,
} ,
{
Name : "Mobile App (long version, truncated)" ,
UserAgent : "Mattermost Mobile/233.234441.341234223421341234529099823109834440981234+abcdef3214eafeabc3242331129857301afesfffff1930a84e4bd2348fe129ac1309bd929dca3419af934bfe3089fcd (Android; 13; sdk_gphone64_arm64)" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "233.234441.341234223421341234529099823109834440981234+abcdef3214eafeabc3242331129857301afesfffff1930a84e4bd2348fe129ac1309bd929d" ,
} ,
{
Name : "Firefox (Mac)" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Firefox" ,
ExpectedBrowserVersion : "132.0" ,
} ,
{
Name : "Desktop App (Mac)" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.127 Electron/31.2.1 Safari/537.36 Mattermost/5.9.0" ,
ExpectedPlatformName : "Macintosh" ,
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Desktop App" ,
ExpectedBrowserVersion : "5.9.0" ,
} ,
{
Name : "Mobile App (Android, Samsung Galaxy Fold Z)" ,
UserAgent : "Mattermost Mobile/2.20.0+6000556 (samsung/q4qcsx/q4q:14/UP1A.231005.007/F936WVLU4FXE3:user/release-keys; 14; SM-F936W)" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "2.20.0+6000556" ,
} ,
{
Name : "Chrome (Android)" ,
UserAgent : "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Chrome" ,
ExpectedBrowserVersion : "129.0" ,
} ,
{
Name : "iOS App (iPhone 13)" ,
UserAgent : "Mattermost Mobile/2.20.0+556 (iOS; 17.5.1; iPhone 13)" ,
ExpectedPlatformName : "iPhone" ,
ExpectedOSName : "iOS" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "2.20.0+556" ,
} ,
{
Name : "Safari (iPhone 13)" ,
UserAgent : "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1" ,
ExpectedPlatformName : "iPhone" ,
ExpectedOSName : "iOS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "17.5" ,
} ,
{
Name : "iOS App (iPad 11 Pro)" ,
UserAgent : "Mattermost Mobile/2.21.0+567 (iPadOS; 17.6.1; iPad Pro (11-inch) (1st generation))" ,
ExpectedPlatformName : "iPad" ,
ExpectedOSName : "iOS" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "2.21.0+567" ,
} ,
{
Name : "Safari (iPad 11 Pro, default)" ,
UserAgent : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15" ,
ExpectedPlatformName : "Macintosh" , // iPad pretends to be a desktop Mac by default
ExpectedOSName : "Mac OS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "17.6" ,
} ,
{
Name : "Safari (iPad 11 Pro, requesting mobile site)" ,
UserAgent : "Mozilla/5.0 (iPad; CPU OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1" ,
ExpectedPlatformName : "iPad" ,
ExpectedOSName : "iOS" ,
ExpectedBrowserName : "Safari" ,
ExpectedBrowserVersion : "17.6" ,
} ,
// MM-67274: User agents with empty version strings should not panic
{
Name : "Mobile App (no version)" ,
UserAgent : "Mattermost Mobile/" ,
ExpectedPlatformName : "Linux" ,
ExpectedOSName : "Android" ,
ExpectedBrowserName : "Mobile App" ,
ExpectedBrowserVersion : "0.0" ,
} ,
{
Name : "Desktop App (no version)" ,
UserAgent : "Mattermost/" ,
ExpectedPlatformName : "Unknown" ,
ExpectedOSName : "" ,
ExpectedBrowserName : "Desktop App" ,
ExpectedBrowserVersion : "0.0" ,
} ,
{
Name : "mmctl (no version)" ,
UserAgent : "mmctl/" ,
ExpectedPlatformName : "Unknown" ,
ExpectedOSName : "" ,
ExpectedBrowserName : "mmctl" ,
ExpectedBrowserVersion : "0.0" ,
} ,
{
Name : "Franz (no version)" ,
UserAgent : "Franz/" ,
ExpectedPlatformName : "Unknown" ,
ExpectedOSName : "" ,
ExpectedBrowserName : "Unknown" ,
ExpectedBrowserVersion : "0.0" ,
} ,
2018-05-09 12:25:03 -04:00
}
func TestGetPlatformName ( t * testing . T ) {
2025-05-30 07:58:26 -04:00
mainHelper . Parallel ( t )
2026-01-29 13:12:35 -05:00
for _ , tc := range testUserAgents {
t . Run ( tc . Name , func ( t * testing . T ) {
ua := uasurfer . Parse ( tc . UserAgent )
actual := getPlatformName ( ua , tc . UserAgent )
assert . Equal ( t , tc . ExpectedPlatformName , actual )
2018-05-09 12:25:03 -04:00
} )
}
}
func TestGetOSName ( t * testing . T ) {
2025-05-30 07:58:26 -04:00
mainHelper . Parallel ( t )
2026-01-29 13:12:35 -05:00
for _ , tc := range testUserAgents {
t . Run ( tc . Name , func ( t * testing . T ) {
ua := uasurfer . Parse ( tc . UserAgent )
actual := getOSName ( ua , tc . UserAgent )
assert . Equal ( t , tc . ExpectedOSName , actual )
2018-05-09 12:25:03 -04:00
} )
}
}
func TestGetBrowserName ( t * testing . T ) {
2025-05-30 07:58:26 -04:00
mainHelper . Parallel ( t )
2026-01-29 13:12:35 -05:00
for _ , tc := range testUserAgents {
t . Run ( tc . Name , func ( t * testing . T ) {
ua := uasurfer . Parse ( tc . UserAgent )
actual := getBrowserName ( ua , tc . UserAgent )
assert . Equal ( t , tc . ExpectedBrowserName , actual )
2018-05-09 12:25:03 -04:00
} )
}
}
func TestGetBrowserVersion ( t * testing . T ) {
2025-05-30 07:58:26 -04:00
mainHelper . Parallel ( t )
2026-01-29 13:12:35 -05:00
for _ , tc := range testUserAgents {
t . Run ( tc . Name , func ( t * testing . T ) {
ua := uasurfer . Parse ( tc . UserAgent )
actual := getBrowserVersion ( ua , tc . UserAgent )
assert . Equal ( t , tc . ExpectedBrowserVersion , actual )
2018-05-09 12:25:03 -04:00
} )
}
}
2026-03-04 10:16:11 -05:00
func TestGetDesktopAppVersion ( t * testing . T ) {
tests := [ ] struct {
ua string
version string
ok bool
} {
{ "Mattermost/5.0.0" , "5.0.0" , true } ,
{ "Mattermost/5.3.1 Chrome/110.0.5481.177" , "5.3.1" , true } ,
{ "Mozilla/5.0 ... Mattermost/5.9.0" , "5.9.0" , true } ,
{ "Mattermost/5.0.0-alpha" , "5.0.0-alpha" , true } ,
{ "Mattermost/6.0.0-rc.1 Electron/31.2.1" , "6.0.0-rc.1" , true } ,
{ "Mattermost Mobile/1.2.3" , "" , false } ,
{ "Mozilla/5.0 Chrome/120.0.0" , "" , false } ,
{ "Mattermost/" , "" , false } ,
{ "" , "" , false } ,
{ " " , "" , false } ,
{ "Mattermost" , "" , false } ,
{ "Mattermost 5.0.0" , "" , false } ,
{ "Mattermost/ \t" , "" , false } ,
{ "MATTERMOST/5.0.0" , "" , false } ,
{ "mattermost/5.0.0" , "" , false } ,
{ "mmctl/1.2.3" , "" , false } ,
{ "Franz/4.0.4 Chrome/52.0.2743.82 Electron/1.3.1" , "" , false } ,
{ "MattermostMobile/1.0" , "" , false } ,
{ "SomeMattermost/2.0.0" , "" , false } ,
{ "Chrome/120.0.0 SomeMattermost/2.0.0" , "" , false } ,
}
for _ , tt := range tests {
t . Run ( tt . ua , func ( t * testing . T ) {
version , ok := GetDesktopAppVersion ( tt . ua )
assert . Equal ( t , tt . ok , ok )
assert . Equal ( t , tt . version , version )
} )
}
}