// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package states import ( "reflect" "github.com/opentofu/opentofu/internal/addrs" ) // Equal returns true if the receiver is functionally equivalent to other, // including any ephemeral portions of the state that would not be included // if the state were saved to files. // // To test only the persistent portions of two states for equality, instead // use statefile.StatesMarshalEqual. func (s *State) Equal(other *State) bool { // For the moment this is sufficient, but we may need to do something // more elaborate in future if we have any portions of state that require // more sophisticated comparisons. return reflect.DeepEqual(s, other) } // ManagedResourcesEqual returns true if all of the managed resources tracked // in the reciever are functionally equivalent to the same tracked in the // other given state. // // This is a more constrained version of Equal that disregards other // differences, including but not limited to changes to data resources and // changes to output values. func (s *State) ManagedResourcesEqual(other *State) bool { // First, some accommodations for situations where one of the objects is // nil, for robustness since we sometimes use a nil state to represent // a prior state being entirely absent. if s == nil && other == nil { return true } if s == nil { return !other.HasManagedResourceInstanceObjects() } if other == nil { return !s.HasManagedResourceInstanceObjects() } // If we get here then both states are non-nil. // sameManagedResources tests that its second argument has all the // resources that the first one does, so we'll call it twice with the // arguments inverted to ensure that we'll also catch situations where // the second has resources that the first does not. return sameManagedResources(s, other) && sameManagedResources(other, s) } func sameManagedResources(s1, s2 *State) bool { for _, ms := range s1.Modules { for _, rs := range ms.Resources { addr := rs.Addr if addr.Resource.Mode != addrs.ManagedResourceMode { continue } otherRS := s2.Resource(addr) if !reflect.DeepEqual(rs, otherRS) { return false } } } return true }