github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/transforms/transforms_test.go (about)

     1  /*
     2   * Copyright (c) 2022, Psiphon Inc.
     3   * All rights reserved.
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package transforms
    21  
    22  import (
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
    28  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
    29  )
    30  
    31  func TestTransforms(t *testing.T) {
    32  	err := runTestTransforms()
    33  	if err != nil {
    34  		t.Fatalf(errors.Trace(err).Error())
    35  	}
    36  }
    37  
    38  func runTestTransforms() error {
    39  
    40  	transformNameAny := "exampleTransform1"
    41  	transformNameScoped := "exampleTransform2"
    42  	scopeName := "exampleScope"
    43  
    44  	specs := Specs{
    45  		transformNameAny: Spec{[2]string{"x", "y"}},
    46  		transformNameScoped: Spec{
    47  			[2]string{"aa", "cc"},
    48  			[2]string{"bb", "(dd|ee)"},
    49  			[2]string{"^([c0]{6})", "\\$\\{1\\}ff0"},
    50  		},
    51  	}
    52  
    53  	scopedSpecs := ScopedSpecNames{
    54  		SCOPE_ANY: []string{transformNameAny},
    55  		scopeName: []string{transformNameScoped},
    56  	}
    57  
    58  	// Test: validation
    59  
    60  	err := specs.Validate()
    61  	if err != nil {
    62  		return errors.Trace(err)
    63  	}
    64  
    65  	err = scopedSpecs.Validate(specs)
    66  	if err != nil {
    67  		return errors.Trace(err)
    68  	}
    69  
    70  	// Test: select based on scope
    71  
    72  	name, spec := specs.Select(SCOPE_ANY, scopedSpecs)
    73  	if name != transformNameAny || !reflect.DeepEqual(spec, specs[transformNameAny]) {
    74  		return errors.TraceNew("unexpected select result")
    75  	}
    76  
    77  	name, spec = specs.Select(scopeName, scopedSpecs)
    78  	if name != transformNameScoped || !reflect.DeepEqual(spec, specs[transformNameScoped]) {
    79  		return errors.TraceNew("unexpected select result")
    80  	}
    81  
    82  	// Test: correct transform (assumes spec is transformNameScoped)
    83  
    84  	seed, err := prng.NewSeed()
    85  	if err != nil {
    86  		return errors.Trace(err)
    87  	}
    88  
    89  	input := "aa0aa0aa0bb0aa0bb0aa0bb0aa0bb0aa0bb0aa0bb0aa0bb0aa0bb0aa0bb0aa"
    90  	output, err := spec.Apply(seed, input)
    91  	if err != nil {
    92  		return errors.Trace(err)
    93  	}
    94  
    95  	if !strings.HasPrefix(output, "cc0cc0ff0") ||
    96  		strings.IndexAny(output, "ab") != -1 ||
    97  		strings.IndexAny(output, "de") == -1 {
    98  		return errors.Tracef("unexpected apply result: %s", output)
    99  	}
   100  
   101  	// Test: same result with same seed
   102  
   103  	previousOutput := output
   104  
   105  	output, err = spec.Apply(seed, input)
   106  	if err != nil {
   107  		return errors.Trace(err)
   108  	}
   109  
   110  	if output != previousOutput {
   111  		return errors.Tracef("unexpected different apply result")
   112  	}
   113  
   114  	// Test: different result with different seed (with high probability)
   115  
   116  	different := false
   117  	for i := 0; i < 1000; i++ {
   118  
   119  		seed, err = prng.NewSeed()
   120  		if err != nil {
   121  			return errors.Trace(err)
   122  		}
   123  
   124  		output, err = spec.Apply(seed, input)
   125  		if err != nil {
   126  			return errors.Trace(err)
   127  		}
   128  
   129  		if output != previousOutput {
   130  			different = true
   131  			break
   132  		}
   133  	}
   134  
   135  	if !different {
   136  		return errors.Tracef("unexpected identical apply result")
   137  	}
   138  
   139  	return nil
   140  }